使用存储库模式在 Entity Framework 中添加具有相关子对象的记录
Adding record with related child object in Entity Framework using Repository Pattern
我在向包含与现有对象的关系的数据库中添加实体时遇到问题。我搜索了很多,找不到合适的解决方案。我会尽可能简单地描述这个。
public class Store : IEntity
{
public int StoreId { get; set; }
public string StoreName { get; set; }
public virtual Address Address { get; set; }
public virtual Contractor Contractor { get; set; }
}
public class Product : IEntity
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public virtual Store Store { get; set; }
}
并在存储库中添加这样的记录。这是通用的 class
public TEntity Add(TEntity entity)
{
using (var context = new TContext())
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
return entity;
}
}
现在当我尝试添加这样的新记录时
var store = storeManager.GetBy(x => x.StoreId == 1);
var product = new Product() { ProductName = "Bananas", Store = store };
productManager.Add(product);
productManager.GetAll().ForEach(x => Console.WriteLine(x.ProductName + " " + x.Store.StoreId));
商店关系被添加为新商店并获得新 ID。有人知道我该如何解决这个问题吗?
来自数据库的示例:
StoreId StoreName Address_AddressId Contractor_ContractorId
1 NULL 1 1
2 NULL 2 2
3 NULL 3 3
4 NULL 4 4
5 NULL 5 5
6 NULL 6 6
7 NULL 7 7
这是我关于 Whosebug 的第一个问题。
您的问题最可能的原因是您正在为插入操作创建上下文的一个新实例。因此,这个新上下文不仅获得了一个新产品,还获得了一个商店,这是从另一个上下文接收的,但是这个新创建的上下文不知道商店已经在数据库中。
一个普遍的问题是不正确地管理数据库上下文的生命周期。 EF 实例与用于接收它们的上下文相关联,您不能只是将实体从一个上下文放入另一个上下文。
您应该在多个管理器之间共享数据库上下文的实例,而不是在您的每个管理器操作中创建一个新的上下文。
public class StoreManager
{
public StoreManager( Context context )
{
this.context = context;
}
public TEntity Add(TEntity entity)
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
return entity;
}
}
编排必须首先创建上下文并确保它在两个管理器之间共享
var context = new DbContext();
var storeManager = new StoreManager( context );
var productManager = new ProductManager( context );
var store = storeManager.GetBy(x => x.StoreId == 1);
var product = new Product() { ProductName = "Bananas", Store = store };
productManager.Add(product);
productManager.GetAll().ForEach(x => Console.WriteLine(x.ProductName + " " +
x.Store.StoreId));
通常,所有这些都是在一个范围内创建的,例如在请求范围内,因此单个 Web 请求具有单个数据库上下文,并且每个存储库都获得完全相同的上下文实例。
你也可以关注官方tutorial。
我在向包含与现有对象的关系的数据库中添加实体时遇到问题。我搜索了很多,找不到合适的解决方案。我会尽可能简单地描述这个。
public class Store : IEntity
{
public int StoreId { get; set; }
public string StoreName { get; set; }
public virtual Address Address { get; set; }
public virtual Contractor Contractor { get; set; }
}
public class Product : IEntity
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public virtual Store Store { get; set; }
}
并在存储库中添加这样的记录。这是通用的 class
public TEntity Add(TEntity entity)
{
using (var context = new TContext())
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
return entity;
}
}
现在当我尝试添加这样的新记录时
var store = storeManager.GetBy(x => x.StoreId == 1);
var product = new Product() { ProductName = "Bananas", Store = store };
productManager.Add(product);
productManager.GetAll().ForEach(x => Console.WriteLine(x.ProductName + " " + x.Store.StoreId));
商店关系被添加为新商店并获得新 ID。有人知道我该如何解决这个问题吗?
来自数据库的示例:
StoreId StoreName Address_AddressId Contractor_ContractorId
1 NULL 1 1
2 NULL 2 2
3 NULL 3 3
4 NULL 4 4
5 NULL 5 5
6 NULL 6 6
7 NULL 7 7
这是我关于 Whosebug 的第一个问题。
您的问题最可能的原因是您正在为插入操作创建上下文的一个新实例。因此,这个新上下文不仅获得了一个新产品,还获得了一个商店,这是从另一个上下文接收的,但是这个新创建的上下文不知道商店已经在数据库中。
一个普遍的问题是不正确地管理数据库上下文的生命周期。 EF 实例与用于接收它们的上下文相关联,您不能只是将实体从一个上下文放入另一个上下文。
您应该在多个管理器之间共享数据库上下文的实例,而不是在您的每个管理器操作中创建一个新的上下文。
public class StoreManager
{
public StoreManager( Context context )
{
this.context = context;
}
public TEntity Add(TEntity entity)
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
return entity;
}
}
编排必须首先创建上下文并确保它在两个管理器之间共享
var context = new DbContext();
var storeManager = new StoreManager( context );
var productManager = new ProductManager( context );
var store = storeManager.GetBy(x => x.StoreId == 1);
var product = new Product() { ProductName = "Bananas", Store = store };
productManager.Add(product);
productManager.GetAll().ForEach(x => Console.WriteLine(x.ProductName + " " +
x.Store.StoreId));
通常,所有这些都是在一个范围内创建的,例如在请求范围内,因此单个 Web 请求具有单个数据库上下文,并且每个存储库都获得完全相同的上下文实例。
你也可以关注官方tutorial。