11

我开始搞乱 EF 4.0 因为我对 POCO 的可能性感到好奇......我想模拟断开连接的 Web 环境并编写了以下代码来模拟这个:

  1. 在数据库中保存一个测试对象。
  2. 检索测试对象
  3. 处理与我用来检索它的测试对象关联的 DataContext
  4. 更新测试对象
  5. 创建一个新的数据上下文并持久化测试对象上的更改,这些更改在针对我的 POCO 对象生成的 DynamicProxy 中自动跟踪。

问题是当我在上面的 Test 方法中调用 dataContext.SaveChanges 时,没有应用更新。当我检查它的 EntityStateTracker 时,testStore 实体显示“已修改”状态,但是当我在新的 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);
}
4

4 回答 4

8

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

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

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

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

似乎 EF 中没有错误,唯一的方法是使用这样的东西:

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 方法在 SOA 中进行变更跟踪

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

于 2010-04-22T06:22:34.147 回答
5

尝试

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

在调用 SaveChanges 之前

于 2010-05-26T00:57:00.507 回答
2

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

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

using (var dataContext = new DataContext())
{
    dataContext.Stores.ApplyChanges(testStore);
    dataContext.SaveChanges();        
}

至少我已经在我的本地机器上测试过它,并且在这次更新之后它工作了:)
希望这会有所帮助!

于 2010-04-21T19:59:38.797 回答
0

我认为您问题的根源是您对 Context 对象的管理。

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

您可能想在这里阅读一篇关于此的小帖子:http: //social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/5ee5db93-f8f3-44ef-8615-5002949bea71/

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

另一种选择是将属性添加到 poco 的部分类中,以便在将 POCO 从用于加载它的上下文中分离后手动跟踪更改。

于 2010-10-14T14:27:34.123 回答