我注意到实体框架使用.NetCore 1.1和EF 6.1.3在我的内存上下文中复制子对象。有人可以解释这种行为吗?
例如,假设我有以下数据模型:
public class Customer
{
public string Name { get; set; }
public string SomeDataINeed { get; set; }
public int CustomerId { get; set; }
public virtual List<Order> Orders { get; set; }
}
public class Order
{
public string Description { get; set; }
public double BundledDiscount {get; set; }
public int OrderId { get; set; }
public int CustomerId { get; set; }
public virtual Customer Cust { get; set; }
public virtual List<LineItem> LineItems { get; set; }
}
public class LineItem
{
public int OrderId { get; set; }
public int LineItemId { get; set; }
public double LineCost { get; set; }
public virtual Order ParentOrder { get; set; }
}
然后我有一个API端点,我在其中放置一个Order(其LineItems也在put的主体中)然后从数据库中取出Customer。我必须获取完整的客户,因为我需要用一些非持久性数据来装饰它我从另一个API中获取。
当我获取Customer时,LineItems在上下文中重复。例如,如果我在原始放置中有两个LineItem,我现在将有4个,具有重复的主键。
[HttpPut]
public async Task<IActionResult> PutOrder([FromBody] Order order)
{
var customerId = order.CustomerId
_context.Entry(order).State = EntityState.Modified;
_context.SaveChanges();
// now I need to fetch the full customer (just trust me, I need to fetch it).
// After the below call, any Line Items get duplicated inside the context,
// even though they are set up with primary keys.
// For some reason, EF does not use the primary keys to know that some
// line items were already in memory.
var customer = _context.Customer
.Include(x => x.Orders)
.ThenInclude(y => y.LineItems)
.Where(c => c.CustomerId == customerId)
.FirstOrDefault()
return Ok(customer);
}
到目前为止,我发现的唯一解决方案是首先将原始对象从上下文中分离出来......但似乎我不应该这样做。似乎Entity Framework应该能够根据主键和外键自动删除重复。
这是另一个发生了什么的例子。首次EF操作后的上下文:
context: {
Order: {
id: 1,
LineItems: [{id: 33}] // I'm not trying to affect the state here. LineItems are only here because they are in the body of the put
}
}
第二次EF操作后的上下文:
context: {
Customer: {
Order: {
id: 1,
LineItems: [
{id: 33},
{id: 33} // The line item is duplicated here
]
}
}
}
谢谢!
答案 0 :(得分:1)
它正在复制它们,因为正如@Steve Greene所说,当您设置父实体的状态时,子实体不会被修改。就上下文而言,PUT
中的这些订单项是新实体,尽管它们具有主键。
您必须浏览每个子项并将其附加到上下文中。通过这样做,如果他们有主键,则应将其设置为Unchanged
状态;如果他们没有主键,则应将其设置为Added
。