问题描述
的EntityFramework code深处时将引发NullReferenceException(EF错误?),但我的问题是关于实体框架(V5)和异步的WebAPI控制器动作。
一个摄制将很难重新在这里,但在本质上code执行以下操作:
公共类AController:ApiController
{
私人IUow _uow;除其他事项外//,一个的DbContext
// DI构造函数
公共AController(IUow UOW)
{
_uow = UOW;
} [HttpPost]
公共异步任务< Htt的presponseMessage>帖子(型号模型)
{
实体E = _uow.Entity.GetById(model.id);
等待IO_Ops_Async(模型);
新ModelAdapter()UpdateEntity(实体模型);
_uow.Commit(); < - 抛出的异常此调用过程 - 见下文
... //做一些与返回结果
}
}
在提交()
,前刚刚 DbContext.SaveChanges()
,我们通过所有<$ C $循环C> DbChangeTracker.Entries()来设置一些常用的属性。不过这是项()
与单个循环之前误差的的NullReferenceException
内心深处 System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
下面是调用堆栈。这是所有框架code和感觉就像一个错误,但我的问题确实是如果两者之间的DbContext呼叫允许上述异步/等待使用。在任何时候,我们多线程 - 异步/的await只用,因为有我们可以使用异步/的await设施(一对夫妇的HttpClient下载+一些异步磁盘I / O的)
执行一些IO操作。 System.NullReferenceException:对象不设置到对象的实例\\ r \\ n。
在System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity,布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.EntityReference`1.Include(布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity,布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity,布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.EntityCollection`1.Include(布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity,布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity,布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.EntityReference`1.Include(布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity,布尔addRelationshipAsUnchanged,布尔doAttach)\\ r \\ n
在System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget,布尔applyConstraints,布尔addRelationshipAsUnchanged,布尔relationshipAlreadyExists,布尔allowModifyingOtherEndOfRelationship,布尔forceForeignKeyChanges)\\ r \\ n
在System.Data.Objects.ObjectStateManager.PerformAdd(IEntityWrapper wrappedOwner,RelatedEnd relatedEnd,IEntityWrapper entityToAdd,布尔isForeignKeyChange)\\ r \\ n
在System.Data.Objects.ObjectStateManager.PerformAdd(IList`1项)\\ r \\ n
在System.Data.Objects.ObjectStateManager.DetectChanges(个)\\ r \\ n
在System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate个)\\ r \\ n
在System.Data.Entity.Infrastructure.DbChangeTracker.Entries(个)\\ r \\ n
有后的隐式线程切换等待
,造成IO完成。据我所知,EF5可能无法处理这种因为它使用线程本地存储。
OTOH,EF6.x(特别是最新版本)应该是在这种情况下正常工作。
相关:
更新以报告的评价:
The EF5 source code is not open-sourced (unlike with EF6), so I cannot be 100% sure, but I suspect EF5 explicitly uses TLS (i.e., ThreadStatic
or ThreadLocal<T>
). There is no way all TLS properties could be automatically flowed by ExecutionContext
. It would be a huge breaking change and security threat to the existing code (let alone it might not even be technically possible to implement this).
ExecutionContext
captures and flows a very specific subset of thread properties. This subset is undocumented, but you can learn more about it here.
It's a responsibly of the specific class implementation to flow its static properties across multiple threads, there's CallContext.LogicalSetData
/CallContext.LogicalGetData
for that. I believe this is what EF6 does under the hood.
这篇关于实体框架5螺纹敏捷的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!