我先使用实体框架代码,然后通过wcf rest http接口公开northwind数据库。
我没有公开orderdetails表(order items),因为创建一个订单然后通过另一个服务分别添加每个所需的orderdetails是没有意义的。在我看来,它必须是一个原子事务,要么作为一个成功,要么作为一个失败。因此,我在传递给客户机时包含order.orderdetails集合,并假设在创建或更新订单时会得到一个。
但是,问题似乎是在重新附加更新的order实体时检测到orderdetails集合的更改。可以将订单本身设置为“修改”以更新这些属性,但这不会级联到orderdetail项。所以我可以手动检查并将更新的设置为“修改”,但问题在于首先找出哪些是更新的。将新的orderdetail设置为modified将在尝试保存时导致错误。
我阅读了一个建议,将新集合项的ID设置为0,并在服务器中使用它来确定它是新的还是现有的。不过,northwind在orderid和productid之间为orderdetails使用复合键。这两个都必须由客户设置,所以我找不到检测新功能的方法。此外,删除的Orror细节不会存在于分离图中,我需要确定删除了哪些内容并显式删除它。
任何建议都将不胜感激。

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;
}

最佳答案

这是common and complex issue没有魔法能帮你。我的解决方案(也是唯一一个在所有场景中都有效的解决方案)是在更新方法中再次加载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;
}

如果使用时间戳,也可能需要手动检查它们。
替代方案是您所描述的,0用于新的详细信息,负id用于已删除的详细信息,但这是必须在客户机上完成的逻辑。它也只在某些情况下有效。

08-05 02:34