将相同的对象附加到Entity Framework 6中的不同上下文

时间:2014-03-18 13:57:16

标签: c# multithreading entity-framework-6

从我读到的所有内容到现在,不应该将相同的对象附加到不同的dbcontexts(在这种情况下,我能找到的所有示例和问题都显示异常)。现在,当我使用EF6进行测试时,它允许我将相同的对象附加到不同的上下文(来自不同的线程);我甚至能够从一个线程更改对象并将其与另一个线程一起保存。 这不一定是坏事(除了事实我必须确保我一直锁定,因为没有抛出异常),只是我想了解发生了什么。

有人知道这是否真的是一个新功能"在EF6?

这里有一些代码。从几个不同的线程调用它没有异常,如果我在保存之前从另一个线程更改对象,它将采用最后的值:

                        using (var db = new TestContext())
                        {
                            db.Users.Attach(_cachedUser);
                            MessageBox.Show("attached"); //I use this to pause the thread as long as I want
                            _cachedUser.UserCode = tbCode.Text;
                            _cachedUser.UserDesc = tbDesc.Text;
                            MessageBox.Show("ready to save"); //pause again
                            db.SaveChanges();
                        }

修改 收到答案后,为什么会这样,我还找到了如何检查一个对象是否是代理的:http://msdn.microsoft.com/en-us/library/vstudio/ee835846(v=vs.100).aspx

public static bool IsProxy(object type)
{
    return type != null && ObjectContext.GetObjectType(type.GetType()) != type.GetType();
}

工作得很好。

1 个答案:

答案 0 :(得分:7)

这是可能的,因为实体框架引入了代码优先的样式,因为您只能使用POCO执行此操作。

cachedUser是一个简单的C#类。它没有关于它附加的上下文的任何信息。此外,新的上下文实例不了解另一个上下文的更改跟踪器。因此,无法检查POCO是否附加到任何地方的上下文。

cachedUser不是POCO而是代理对象时,这会发生变化。 (代理对象是EF在运行中创建的对象。它继承自实体类,它包含启用延迟加载和促进更改跟踪的代码和状态)。当您尝试将代理对象附加到第二个上下文时,您将获得异常:

  

IEntityChangeTracker的多个实例无法引用实体对象。

这就是为什么在许多情况下,建议创建代理而不是POCO。您可以使用db.Users.Create()代替new User()来创建代理。

何时创建代理,是否可以实现这一点以及何时EF物化代理是一个超出此问题范围的主题。有关这方面的更多信息,请访问here