簡體   English   中英

為什么未出現以阻止在EF上下文中進行第二次操作

[英]Why Does Await Not Appear to Prevent Second Operation on EF Context

在ASP.NET MVC應用程序中,對於使用我的實體框架上下文的一種控制器方法,我收到以下錯誤消息。

在先前的異步操作完成之前,第二操作在此上下文上開始。 使用“ await”來確保在此上下文上調用另一個方法之前,所有異步操作都已完成。 不保證任何實例成員都是線程安全的。

我知道您不能並行運行查詢,並且一切似乎都已正確等待。 如果我調試程序並逐步檢查從EF返回的一些數據,則它可以工作,可能是因為這迫使查詢完成。

編輯如果我把一個斷點在控制器方法空校驗和檢查的數據shipmentDetail的沒有拋出異常。

這是代碼片段:

控制器方式

[Route("{id:int}/Deliveries")]
public async Task<ActionResult> DeliveryInfo(int id)
{
    var shipmentDetail = await db.ShipmentDetails.SingleOrDefaultAsync(s => s.Id == id);
    if (shipmentDetail == null)
        return HttpNotFound(string.Format("No shipment detail found with id {0}", id));
     var model = await DeliveryInfoModel.CreateModel(db, shipmentDetail);
    return View("DeliveryInfo", model);
}

CreateModel方法

public static async Task<DeliveryInfoModel> CreateModel(Context db, ShipmentDetail shipment)
{
    DeliveryInfoModel model = new DeliveryInfoModel()
    {
        ShipmentInfo = shipment
    };

    //initialize processing dictionary
    Dictionary<int, bool> boxesProcessed = new Dictionary<int, bool>();
    List<DeliveryBoxStatus> statuses = new List<DeliveryBoxStatus>();

     for (int i = 1; i <= shipment.BoxCount; i++ )
        {
            boxesProcessed.Add(i, false);
        }

        //work backwards through process

        //check for dispositions from this shipment
        if(shipment.Dispositions.Count > 0)
        {
             foreach (var d in shipment.Dispositions)
            {
                DeliveryBoxStatus status = new DeliveryBoxStatus()
                {
                    BoxNumber = d.BoxNumber,
                    LastUpdated = d.Date,
                    Status = d.Type.GetDescription().ToUpper()
                };

                statuses.Add(status);
                boxesProcessed[d.BoxNumber] = true;
            }
        }

        //return if all boxes have been accounted for
        if (boxesProcessed.Count(kv => kv.Value) == shipment.BoxCount)
        {
            model.BoxStatuses = statuses;
            return model;
        }

        //check for deliveries
        if(shipment.Job_Detail.Count > 0)
        {
            foreach (var j in shipment.Job_Detail.SelectMany(d => d.DeliveryInfos))
            {
                DeliveryBoxStatus status = new DeliveryBoxStatus()
                {  
                    BoxNumber = j.BoxNumber,
                    LastUpdated = j.Job_Detail.To_Client.GetValueOrDefault(),
                    Status = "DELIVERED"
                };

                statuses.Add(status);
                boxesProcessed[j.BoxNumber] = true;
            }
        }

    //check for items still in processing & where
    foreach (int boxNum in boxesProcessed.Where(kv => !kv.Value).Select(kv => kv.Key))
    {
       //THIS LINE THROWS THE EXCEPTION
        var processInfo = await db.Processes.Where(p => p.Jobs__.Equals(shipment.Job.Job__, StringComparison.InvariantCultureIgnoreCase) && p.Shipment == shipment.ShipmentNum && p.Box == boxNum)
                                .OrderByDescending(p => p.date)
                                .FirstOrDefaultAsync();

       //process returned data
       //...
    }

    model.BoxStatuses = statuses;

    return model;
}

我不確定是由於控制器中的查詢還是由於循環中的查詢未完成導致此行為。 由於EF的懶惰,何時真正執行/返回查詢,或者在這種情況下異步/等待如何工作,我是否不了解? 我還有很多其他方法和控制器可以進行異步EF調用,並且以前沒有遇到過這種情況。

編輯

我的上下文是使用Ninject作為我的IoC容器注入到我的控制器中的。 這是NinjectWebCommon的RegisterServices方法內部的配置:

kernel.Bind<Context>().ToSelf().InRequestScope();

與Entity Framework異步使用時,請避免延遲加載。 取而代之的是,要么先加載您需要的數據,要么使用Include()來確保查詢中加載了您需要的數據。

https://msdn.microsoft.com/zh-CN/magazine/dn802603.aspx

異步支持的當前狀態

...異步支持已在版本6中添加到了Entity Framework(在EntityFramework NuGet包中)。 但是,由於異步加載始終是同步執行的,因此必須小心避免延遲加載 ...

(強調我的)

也:

https://entityframework.codeplex.com/wikipage?title=基於任務的%20Asynchronous%20Pattern%20support%20in%20EF。#ThreadSafety

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM