.net 4.0 使用POCO动态代理跨多个数据上下文跟踪Entity Framework 4.0中的更改

.net 4.0 使用POCO动态代理跨多个数据上下文跟踪Entity Framework 4.0中的更改,.net-4.0,poco,entity-framework-4,.net 4.0,Poco,Entity Framework 4,我开始玩EF4.0是因为我对POCO的可能性很好奇。。。我想模拟断开连接的web环境,并编写了以下代码来模拟: 在数据库中保存测试对象 检索测试对象 处理与我用来检索它的测试对象关联的DataContext 更新测试对象 创建一个新的数据上下文,并保存测试对象上的更改,这些更改在针对我的POCO对象生成的DynamicProxy中自动跟踪 问题是,当我在上面的测试方法中调用dataContext.SaveChanges时,不会应用更新。当我检查其EntityStateTracker时,testS

我开始玩EF4.0是因为我对POCO的可能性很好奇。。。我想模拟断开连接的web环境,并编写了以下代码来模拟:

  • 在数据库中保存测试对象
  • 检索测试对象
  • 处理与我用来检索它的测试对象关联的DataContext
  • 更新测试对象
  • 创建一个新的数据上下文,并保存测试对象上的更改,这些更改在针对我的POCO对象生成的DynamicProxy中自动跟踪
  • 问题是,当我在上面的测试方法中调用dataContext.SaveChanges时,不会应用更新。当我检查其EntityStateTracker时,testStore实体显示“Modified”状态,但当我在新dataContext的Stores属性中查看它时,它不再被修改。我本以为在新的dataContext上调用Attach方法也会使对象的“修改”状态结束,但事实似乎并非如此。我有什么遗漏吗?我肯定在使用DynamicProxies与自跟踪POCO合作

    private static void SaveTestStore(string storeName = "TestStore")
    {
      using (var context = new DataContext())
      {
        Store newStore = context.Stores.CreateObject();
        newStore.Name = storeName;
        context.Stores.AddObject(newStore);
        context.SaveChanges();
      }
    }
    
    private static Store GetStore(string storeName = "TestStore")
    {
      using (var context = new DataContext())
      {
        return (from store in context.Stores
                where store.Name == storeName
                select store).SingleOrDefault();
      }
    }
    
    [Test]
    public void Test_Store_Update_Using_Different_DataContext()
    {
      SaveTestStore();
      Store testStore = GetStore();
      testStore.Name = "Updated";      
    
      using (var dataContext = new DataContext())
      {
        dataContext.Stores.Attach(testStore);
        dataContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);        
      }
    
      Store updatedStore = GetStore("Updated");
      Assert.IsNotNull(updatedStore);
    }
    

    在玩了自我跟踪实体之后,我意识到你犯了什么错误。 与其尝试将实体附加到数据上下文,不如指示希望数据上下文将对其所做的新更改应用到数据库

    在这种情况下,将“保存”代码更改为:

    using (var dataContext = new DataContext())
    {
        dataContext.Stores.ApplyChanges(testStore);
        dataContext.SaveChanges();        
    }
    
    至少我已经在我的本地机器上测试了它,并且在这次更新之后它工作了:)

    希望这有帮助

    如您稍后所述,您使用的是POCO生成器,而不是自跟踪实体生成器

    我也试过了,变得很困惑。代理类似乎没有像预期的那样工作,并且可能存在错误。再说一遍。MSDN上的示例中没有一个尝试过类似的操作,当它们引用应用程序不同层中的更新时(就像我们在这里所做的),它们使用自跟踪实体,而不是POCO代理

    我不确定这些代理是如何工作的,但它们似乎确实存储了某种状态(我设法在私有属性中找到了“修改”的状态)。但这一特性似乎被完全忽略了。将属性附加到上下文时,上下文将向ObjectStateManager添加一个条目,并在其中存储进一步的状态更新。在这一点上,如果您进行了更改,它将被注册并应用

    问题是,当您附加实体时,代理中修改的状态不会传输到上下文中的状态管理器。此外,如果您使用context.Refresh(),更新将被覆盖,并被遗忘!即使您将RefreshMode.ClientWins传递给它。我尝试将对象状态的state属性设置为modified,但它仍然被覆盖,并且恢复了原始设置

    似乎EF中存在一个bug,而唯一的解决方法是使用如下内容:

    using (var db = new Entities())
    {
        var newUser = (from u in db.Users
                        where u.Id == user.Id
                        select u).SingleOrDefault();
        db.Users.ApplyCurrentValues(user);
        db.SaveChanges();
    }
    
    还有一件事

    似乎POCO不支持您正在寻找的方法,正如我所料,创建自跟踪实体是为了解决您正在测试的情况,而POCO的代理仅在它们创建的上下文中跟踪更改。。或者看起来是这样…

    试试看

            db.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Modified);
    

    在调用SaveChanges之前,我认为问题的根源在于对上下文对象的管理

    POCO处理上下文时,不会通知该上下文上的实体它们不再与上下文关联。POCO的更改跟踪都是由上下文管理的,因此您会遇到一些有趣的问题,其中POCO的行为就像它仍然附加到一个上下文,但实际上它不是,重新附加到另一个上下文应该会引发附加到多个上下文的错误

    这里有一篇关于这一点的小帖子,你可能想读到:

    如果你切换到自我跟踪,我想你会发现你的实体以你想要的方式工作


    另一个选项是在将poco从用于加载它的上下文中分离出来后,向poco的分部类添加属性,以手动跟踪更改。

    您是如何让ApplyChanges()方法显示的?我一定是做错了什么,因为那种方法对我来说并不存在……哦,我明白了。您使用的是自跟踪实体代码生成模板,而我使用的是POCO模板。有了POCO模板,实体通过一些诡计来跟踪自己,方法是使用一些特殊的更改跟踪功能在运行时使用DynamicProxy覆盖POCO对象。在尝试了似乎所有的东西之后,我无法让我的原始问题中的场景正常工作。我最初用POCO实体开始了测试,但我找不到一种方法来获取对象的“状态”(修改/未更改),而你说它在那里。在重读你的帖子后,我看到“我肯定在使用自跟踪POCO”,所以我尝试了自跟踪模板。。。那么你从哪里得到物体的状态?嘿,罗伯。。。你看到你问题的第二个答案了吗?从那以后就没有你的消息了。。我不知道你怎么想谢谢你的辛勤工作!事实上,POCO只是在其创建的环境中进行跟踪,这是非常不幸的。我几乎希望这是一个bug,而不仅仅是它是如何设计的。我试图避免在保存期间从数据库重新加载实体。。。随着原始实体和更新实体都加载,当然很容易知道是否发生了更改。+1指出POCO模板生成的实体和STE POCO模板生成的实体之间的区别请注意,Mrs实体框架本身Julie Lerman也提出了此解决方案