从我读到的所有内容到现在,不应该将相同的对象附加到不同的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();
}
工作得很好。
答案 0 :(得分:7)
这是可能的,因为实体框架引入了代码优先的样式,因为您只能使用POCO执行此操作。
cachedUser
是一个简单的C#类。它没有关于它附加的上下文的任何信息。此外,新的上下文实例不了解另一个上下文的更改跟踪器。因此,无法检查POCO是否附加到任何地方的上下文。
当cachedUser
不是POCO而是代理对象时,这会发生变化。 (代理对象是EF在运行中创建的对象。它继承自实体类,它包含启用延迟加载和促进更改跟踪的代码和状态)。当您尝试将代理对象附加到第二个上下文时,您将获得异常:
IEntityChangeTracker的多个实例无法引用实体对象。
这就是为什么在许多情况下,建议创建代理而不是POCO。您可以使用db.Users.Create()
代替new User()
来创建代理。
何时创建代理,是否可以实现这一点以及何时EF物化代理是一个超出此问题范围的主题。有关这方面的更多信息,请访问here。