实体框架Attach()具有共享对象的对象树

时间:2011-12-07 14:58:59

标签: wcf entity-framework

我正在尝试将对象树附加到通过WCF服务调用提供的Entity Framework上下文。有问题的对象具有子项的集合,并且每个子项具有属性,该属性是另一个被跟踪的对象类型。但是,这些最后一项只有一小部分,因此大多数收集项共享它们。像这样的东西(显然,除了EntityObjects):

public class Product
{
  public int Id;
  public string Name;
  public decimal Cost;
}

public class Order
{
  public int Id;
  public List<Detail> details;
}

public class Detail
{
  public int Id;
  public Product Product;
  public int Quantity;
}

每当我的订单具有同一产品的多个详细信息时,实体框架会在附加期间抱怨,因为它试图附加同一产品密钥的多个副本。此信息来自WCF ServiceOperation,因此它被反序列化为Product的离散实例,即使在客户端中它们是一组共享对象。

当Attach发生时,有没有办法告诉EF对象上下文重新使用被跟踪的实体?请注意,我没有直接附加产品,因此检查TryGetObjectStateEntry等技巧将无效。

有什么建议吗?

编辑:

我浏览了以下关于自我跟踪实体的文章(我已经切换到使用),其中包括一些客户端选项,可以作为Slauma的答案的替代方案,它将对帐代码保留在服务器端。 (自我跟踪实体消除了使用Attach()的需要,但仍然存在重复键的问题。)

http://blogs.msdn.com/b/diego/archive/2010/10/06/self-tracking-entities-applychanges-and-duplicate-entities.aspx

1 个答案:

答案 0 :(得分:1)

不,没有办法。在附加之前,您基本上需要使每个键的对象引用唯一,例如:

void PrepareForAttach(Order order)
{
    var dict = new Dictionary<int, Product>();
    foreach (var detail in order.Details)
    {
        Product firstProduct;
        if (dict.TryGetValue(detail.Product.Id, out firstProduct))
            detail.Product = firstProduct;
        else
            dict.Add(detail.Product.Id, detail.Product);
    }
}

EF将关键标识映射到对象引用标识,并且不允许在上下文中具有两个或多个具有相同键的对象。它也不具备使引用唯一的功能,这意味着以某种方式选择您的某个产品,并使用与该键的 正确产品相同的密钥。 (你可能有两个产品具有相同的密钥但不同的其他属性。这个密钥的“正确”产品是什么?EF拒绝决定(并且如果它们都具有相同的值,则不会按属性进行比较)并选择简单安全的模式:抛出异常。)