【问题标题】:Entity Framework duplicating objects in context after re-fetching实体框架在重新获取后在上下文中复制对象
【发布时间】: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


【解决方案1】:

这是复制它们,因为正如@Steve Greene 所说,当您设置父实体的状态时,子实体不会被修改。就上下文而言,PUT 中的那些行项目是新实体,尽管它们具有主键。

您必须遍历每个子项并将其附加到上下文中。通过这样做,如果它们有主键,它应该将它们设置为Unchanged 状态,如果它们没有主键,则设置为Added

【讨论】:

  • 米哈伊尔,谢谢你的解释。我注意到通过使用_context.Order.Update(order) 我没有同样的问题。所以我猜想使用 Update 将更新/附件向下级联,而 EntityState = Modified 只为特定实体设置它。
猜你喜欢
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
相关资源
最近更新 更多