重新附加实体图并检测集合更改

Dan*_*ell 5 c# rest entity-framework entity-framework-4.1

我首先使用实体​​框架代码并通过WCF REST HTTP接口公开northwind数据库.

我没有公开OrderDetails表(订单商品),因为创建订单然后通过另一个服务单独添加每个所需的OrderDetail是没有意义的.在我看来,它需要是一个成功或失败的原子事务.因此,我在传递给客户端时包含Order.OrderDetails集合,并假设在创建或更新订单时我将获得一个.

然而,问题似乎是在重新附加Order实体以进行更新时检测OrderDetails集合的更改.订单本身可以设置为已修改以更新这些属性,但这不会级联到OrderDetail项目.所以我可以手动完成并设置更新的修改后的问题,但问题在于找出哪些是首先更新的.将新的OrderDetail设置为modified会在尝试保存时导致错误.

我读了一条建议,将新集合项的Id设置为0,并在服务器中使用它来决定它是新的还是现有的.然而,Northwind在OrderDetails的OrderID和ProductID之间使用复合键.这些都必须由客户端设置,所以我找不到一种方法来检测新的.此外,已删除的OrderDetail将不存在于分离图中,我将需要弄清楚已删除的内容并明确删除它.

任何建议将不胜感激.

public override Order Update(Order entity)
{
    dbset.Attach(entity);
    DataContext.Entry(entity).State = EntityState.Modified;

    foreach (var orderDetail in entity.OrderDetails)
    {
        DataContext.Entry(orderDetail).State = EntityState.Modified;
    }

    return entity;
}
Run Code Online (Sandbox Code Playgroud)

bre*_*ick 6

我最近被允许开源一些我之前为我的雇主所做的工作(当然有一些变化).我实际上写了一个扩展方法来解决这个问题,你可以在http://refactorthis.wordpress.com/2012/12/11/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-找到它.更新期的一,图的的独立式实体/

希望能帮助到你!


Lad*_*nka 4

这是常见且复杂的问题,没有什么魔法可以为您解决这个问题。我的解决方案(也是唯一适用于所有情况的解决方案)是Order在更新方法中再次加载并手动合并更改:

public override Order Update(Order entity)
{
    // No attach of entity

    var attached = DataContext.Orders.Include(o => o.OrderDetails).SingleOrDefault(...);
    if (attached == null) ...

    // Merge changes from entity to attached - if you change any property
    // it will be marked as modified automatically

    foreach (var detail in attached.OrderDetails.ToList())
    {
        // ToList is necessary because you will remove details from the collection

        // if detail exists in entity check if it must be updated and set its state

        // if detail doesn't exists in entity remove if from collection - if it is \
        // aggregation (detail cannot exists without Order) you must also delete it 
        // from context to ensure it will be deleted from the database
    }

    foreach (var detail in entity.OrderDetails)
    {
        // if it doesn't exists in attached create new detail instance,
        // fill it from detail in entity and add it to attached entity - 
        //you must not use the same instance you got from the entity
    }

    DataContext.SaveChanges();

    return entity;
}
Run Code Online (Sandbox Code Playgroud)

如果使用时间戳,还可能需要手动检查它们。

替代方案是您所描述的,0 用于新详细信息,负 ID 用于删除的详细信息,但这是必须在客户端上完成的逻辑。它也仅在某些情况下有效。