【发布时间】:2014-01-27 16:03:24
【问题描述】:
我们遇到了实体框架为不可为空的关系返回 NULL 值。我们先做模特。
当实体的关系在不同的上下文中(或在我们的实际用例中:不同的线程)发生更改时,就会出现问题。
- 如果导航属性还没有被调用,它将返回 null。
- 如果导航属性在或实体中包含外键属性之前已被调用,它将返回最后一个已知值。
- 为模型启用延迟加载
- 我已经针对实体框架 4.0 和 6.0 进行了测试,它们都产生了相同的结果
这是一个示例模型:
这是一些演示问题的示例测试代码。
int ID;
using (Model1Container1 context = new Model1Container1())
{
Dossier d = new Dossier();
d.Fase = new Fase();
context.DossierSet.AddObject(d);//generate new object with relationship
context.SaveChanges();
ID = d.Id;
}
using (Model1Container1 context = new Model1Container1())
{
Dossier storedDossier = context.DossierSet.Single(x => x.Id == ID);//retrieve the saved entity
using (Model1Container1 context2 = new Model1Container1())
{
Dossier faseDossier = context2.DossierSet.Single(x => x.Id == ID);//modify the saved entity in a different context
faseDossier.Fase = new Fase();
context2.SaveChanges();
}
Console.WriteLine(storedDossier.Fase.Id);//attempt to read the changed property. NULL exception here on storedDossier.Fase
}
这段代码不像我们的实际情况那样使用线程,但它描述了同样的问题。在实际应用程序中,可能有一个完全不同的应用程序在不同的 PC 上修改数据库中的实体。
这里的问题是,为什么会出现这种行为?这可能是实体框架中的错误吗?
我们很清楚,实体框架由于延迟加载而无法检索实体实例化时存在的关系,但为什么它不会加载更改的关系呢?不可为空的实体突然接收到NULL 值是出乎意料的,我们在代码中根本没有考虑到这一点(为什么我们首先要考虑?)
【问题讨论】:
-
发生这种情况是因为每个上下文都意味着不同的事务。您应该将它们称为嵌套在 TransactionScope 中。
-
错误:我们的实体是延迟加载的,这意味着可以在程序中的任何时间调用该属性,远在从数据库中检索到实体之后。与此同时,数据库值可能已经被其他上下文实例更改(例如在线程中)。
-
延迟加载与您的问题无关。您正在调用两个不同的上下文来更新尚未提交的内容。这就是问题所在。您必须像这样使用 TransactionScope:msdn.microsoft.com/en-us/data/dn456843
-
延迟加载与此有关。只有一个上下文更新项目。另一个上下文尚未加载所述项目。延迟加载意味着可以随时加载所述对象,同时它可以在其上下文之外进行更新。这不是更新单个对象的两个上下文。
标签: c# entity-framework c#-4.0 ef-model-first