【发布时间】:2017-10-17 15:20:28
【问题描述】:
我注意到实体框架使用 .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 端点,我在其中放置了一个订单(其 LineItems 也在放置的主体中),然后从数据库中获取客户。我必须获取完整的客户,因为我需要使用从另一个 API 获取的一些非持久性数据来装饰它。
当我获取客户时,LineItems 在上下文中重复。例如,如果我在原始 put 中有两个 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
]
}
}
}
谢谢!
【问题讨论】:
-
设置父级(订单)的 EntityState 不会改变子级(订单项)的状态。见here
-
谢谢史蒂夫,我不想影响孩子们的状态。我只是不希望孩子在我以后上一级并获取父客户时被复制。我在上面添加了另一个插图。
标签: asp.net-core entity-framework-6