其他分享
首页 > 其他分享> > 实体框架5线程敏捷性

实体框架5线程敏捷性

作者:互联网

抛出了EntityFramework代码深处的NullReferenceException(EF错误?),但是我的问题是关于Entity Framework(v5)和WebAPI异步控制器操作的.

在这里很难重新创建一个repro,但是从本质上讲,该代码执行以下操作:

public class AController : ApiController
{
    private IUow _uow; //among other things, a DbContext 
    // DI ctor
    public AController(IUow uow)
    {
        _uow = uow; 
    }

    [HttpPost]
    public async Task<HttpResponseMessage> Post(Model model)
    {
        Entity e = _uow.Entity.GetById(model.id);
        await IO_Ops_Async(model); 
        new ModelAdapter().UpdateEntity(entity, model);
        _uow.Commit(); <- EXCEPTION THROWN DURING THIS CALL - see below
        ... // do something with the return result
    }
}

在Commit()内部,就在DbContext.SaveChanges()之前,我们遍历所有DbChangeTracker.Entries()来设置一些公共属性.但是,在System.Data.Entity.Infrastructure.DbChangeTracker.Entries()深入内部的NullReferenceException循环之前,Entries()会出错.

下面是调用堆栈.所有这些都是Framework代码,感觉像是个bug,但是我的问题确实是,是否允许上面的async / await在DbContext之间调用.我们从来没有使用多线程-仅使用async / await是因为可以使用async / await工具执行一些IO操作(几个Httpclient下载了一些异步磁盘I / O).

System.NullReferenceException: Object reference not set to an instance of an object.\r\n   
at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.EntityReference`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.EntityReference`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.RelatedEnd.WalkObjectGraphToIncludeAllRelatedEntities(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)\r\n   
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)\r\n   
at System.Data.Objects.ObjectStateManager.PerformAdd(IEntityWrapper wrappedOwner, RelatedEnd relatedEnd, IEntityWrapper entityToAdd, Boolean isForeignKeyChange)\r\n   
at System.Data.Objects.ObjectStateManager.PerformAdd(IList`1 entries)\r\n   
at System.Data.Objects.ObjectStateManager.DetectChanges()\r\n   
at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)\r\n   
at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()\r\n

解决方法:

由于IO完成,等待后会有一个隐式线程切换. AFAIK,EF5可能无法处理此问题,因为它使用线程本地存储.

在这种情况下,OTOH,EF6.x(尤其是最新版本)应该可以正常工作.

相关:How to use non-thread-safe async/await APIs and patterns with ASP.NET Web API?

更新以解决评论:

Because the async/await infrastructure supposedly take care and flows
the ExecutionContext (thread-local storage among other “contexts”). I
am asking so that I can make educated changes and preserve the
async/await implementation taking care of whatever specific thing is
breaking EF.

EF5源代码不是开源的(与EF6不同),所以我不能100%确定,但是我怀疑EF5明确使用TLS(即ThreadStatic或ThreadLocal< T>). ExecutionContext不可能自动流动所有TLS属性.这将是对现有代码的巨大突破性变化和安全威胁(更不用说在技术上甚至不可能实现这一点).

ExecutionContext捕获并流动a very specific subset of thread properties.该子集未记录,但您可以了解更多有关here的信息.

跨多个线程传递其静态属性是特定类实现的负责任,为此提供了CallContext.LogicalSetData / CallContext.LogicalGetData.我相信这就是EF6的内幕.

标签:async-await,nullreferenceexception,entity-framework-5,c,entity-framework
来源: https://codeday.me/bug/20191121/2055100.html