【问题标题】:How do I find the source of all the objects that are being tracked for changes in EF CodeFirst CTP5?如何找到正在跟踪 EF CodeFirst CTP5 更改的所有对象的来源?
【发布时间】:2011-03-15 22:34:42
【问题描述】:

我遇到了“一个实体对象不能被多个 IEntityChangeTracker 实例引用”的问题。经过一番检查,似乎我有一个正在跟踪更改的对象。问题是我不知道问题对象的来源......它显然已被放入上下文中,但我不确定哪个调用没有被正确分离。

因此,经过数小时的尝试解决这个问题,我正在寻找如何遍历树以找到与我发生冲突的源对象,因为这可能有助于我了解源对象的位置正在添加中。

错误在第 226 行被抛出,所以看起来我要么存在“隐形”客户,要么可能是客户的属性之一导致了这种情况,因为客户有几个其他属性是他们自己的复杂对象类型...

Line 224:                    if (null != this.Customer)
Line 225:                    {
Line 226:                        context.Entry(this.Customer).State = EntityState.Unchanged;
Line 227:                    } 

错误并没有说明 哪个 对象导致了错误,它只是指向第 226 行。假设它是导致此错误的幻像 Customer 对象,我'试过了:

        var test = ((IObjectContextAdapter)dataContext).ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);

        foreach(var e in test)
        {
            if(e.GetType() == typeof(Customer))
            {
                dataContext.Detach(e);
            }
        }

这个想法是遍历包含所有对象引用的东西,希望找到顽皮的客户并启动它。但是,唉,这行不通。在此循环中找不到客户。哦,仅供参考 - 这是在前面的代码之前运行的几行代码,所以我不会在那里偷偷创建任何额外的对象。

所以我需要一种方法来确定实际上是哪个对象导致了错误。

@Ladislav - 仅供参考 - 我有一个包含所有业务对象 (BO) 的公共库。这个公共库被其他项目使用——Windows 服务、Web 服务等。我试图让每个 BO 负责填充和保存自己,这样我就没有一个 hugo 数据访问类。每个 BO 负责自己的 Save() 方法。以下是 current saveUpdate 方法的示例:

    public void SaveOrUpdate(DataContext context)
    {
        if (context.Entry(this).State == EntityState.Detached)
        {
            context.Customers.Add(this);
            context.SaveChanges();
        }
        else //update
        {
            context.Entry(this).State = System.Data.EntityState.Modified;
            context.SaveChanges();
        }
    }

关于您对范围的建议,我尝试了各种策略 - 乍一看,每个人都说以原子方式进行 - 所以我让每个方法都获取 DataContext 的一个新实例来完成它的工作。这很好用,只要对象不是很复杂,并且不相互依赖,即只包含基本类型属性,如 int 和 string。

但是一旦我开始遇到这些并发错误,我就对其进行了深入研究,发现 DataContext 以某种方式保留了对对象的引用即使它被丢弃这有点疯狂工程,恕我直言。也就是说,如果我将 Customer BO 添加到 DataContext 然后允许 DataContext 超出范围并被 Disposed,然后启动 new DataContext 来做某事,原来的 Customer BO 指针仍然存在!

所以我在 StackOverflow 上阅读了一堆(我可能会补充您的许多答案),Rick Strahl's treatise on DataContext Lifetime Management8 Entity Framework Gotchas by Julia Lerman

所以 Julia 说要放入一个 Dispose 方法,我也这样做了,但它没有帮助,DataContext 仍然神奇地保留了引用。

所以 Rick 说尝试使用“全局”DataContext,这样您就只需要担心一个 DataContext,它应该知道正在发生的一切,所以它不会踩到自己的脚趾。但这似乎也不起作用。公平地说,Rick 说的是 Linq to SQL 和一个网络应用程序,但我有点希望它也适用于我。

然后各种答案说你想要一个全局数据上下文,因为它会变得非常大,非常快,因为它保存了关于你所有对象的所有信息,所以只需使用工作单元的DataContext。

嗯,我已经分解了一个工作单元,它表示对一组对象所做的所有更改、添加和更新,您希望一起完成这些更改、添加和更新。因此,对于我的示例,这里有一些 BO 和属性:

消息组
- 属性:列表
- 属性:客户

客户
- 属性:列表
- 属性:列表

留言
- 属性:客户
- 属性:MessageGroup
- 属性:用户

用户
- 属性:客户
- 属性:列表

当 MessageGroup 到达(作为 Xml)时,系统会对其进行检查和解析。 MessageGroup 构造函数使用依赖注入并将 DataContext 作为其参数之一——因此所有正在创建的“子”BO 都在使用 DataContext 的这一实例。从数据库中获取客户(或创建一个新客户)并分配给 MessageGroup...让我们假设它是一个现有客户 - 所以不需要对其进行更新,它是新鲜的的数据上下文。

然后 MessageGroup.Messages 列表被循环,第一个要创建的 Child BO 是一个新的 User 对象。我将相同的客户对象(来自 MessageGroup)分配给用户。但是,当调用 context.Users.Add(this) 时,我得到了错误。如果我不将客户分配给用户,我不会收到错误消息。

所以现在我有一个来自数据库的新客户(或一个子属性,我不确定),我不需要跟踪这导致我焦虑。我想我可以通过使用类似的东西将它从上下文中删除:

var cust = Customer.GetCustomerFromExternalId(crm.CustomerId);
dataContext.Detach(cust);
dataContext.SaveChanges();

但我仍然收到错误,即使我已明确删除它。当然,如果它是 Customer 的子属性之一,也许它还没有被删除?

目前我想知道存储库模式是否适合我的目的。我还想知道 EF CodeFirst 是否存在根本缺陷或过于复杂?也许我应该改用 SubSonic 或 NHibernate?

【问题讨论】:

  • 还要注意 CTP5 是旧版本。 EF4.1RC 已经发布:microsoft.com/downloads/en/…
  • @Ladislav - “老”有点厚脸皮!它是昨天发布的!
  • 是的 :) 但 CTP5 是不支持的版本 EF4.1 是支持的版本。我稍后会检查您的问题。
  • 我不知道 Julia 描述的那种行为。很有趣。
  • 是的,在浏览论坛时,Juila 似乎对 EF 感到很痛苦!

标签: c# entity-framework entity-framework-4 entity-framework-ctp5 ef-code-first


【解决方案1】:

据我所知,可能没有明确的方法可以从 POCO 实体获取相关上下文 - 动态代理的所有相关属性都是非公开的。要检查 DbContext 中的实体,请使用:

context.ChangeTracker.Entries<Customer>().Where(e => e.State == ...)

避免问题的最佳方法是每个“工作单元”使用单一上下文。如果您有来自多个上下文的实体,您显然不会遵循这种方法。此外,您似乎正在使用多个并发活动上下文。

【讨论】:

  • 嗨 Ladislav,我已经尝试了多种上下文范围的方法 -
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
  • 2010-09-09
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多