簡體   English   中英

System.InvalidOperationException:將數據保存到我的數據庫時

[英]System.InvalidOperationException: when saving data to my database

ASP.Net 核心 blazor 應用程序。 當頁面首次打開時,它會從數據庫中提取維修訂單列表並將它們顯示在頁面上。 這很好用。

數據表有一列帶有“編輯”按鈕。 當您編輯數據時,會彈出一個模式並顯示 RO 信息供其他人編輯。

我的問題是當我單擊“保存”時,出現以下錯誤。

錯誤代碼:

System.InvalidOperationException: '在上一個操作完成之前,第二個操作在此上下文中啟動。 這通常是由不同的線程使用相同的 DbContext 實例引起的,但是不保證實例成員是線程安全的。 這也可能是由在客戶端上評估嵌套查詢引起的,如果是這種情況,請重寫查詢以避免嵌套調用。

值得注意的是這個功能效果很好,我不知道我做了什么讓它失敗。 OnInitAsync() 方法:

protected override async Task OnInitAsync()
    {
        await LoadData();        
    }

加載所有數據的方法:

protected async Task LoadData()
    {
        _repairOrders = await Task.Run(() => RepairOrderService.GetAllRepairOrders().ToArray());
        _vehicleLocations = await Task.Run(() => VehicleLocationService.GetAllLocations().ToArray());
        _repaitStages = await Task.Run(() => RepairStageService.GetAllRepairStages().ToArray());
        _employees = await Task.Run(() => EmployeeService.GetAllEmployees().ToArray());
    }

為保存數據而調用的方法。

protected async Task SaveRepairOrder()
    {
        if (ro.Id != 0)
        {
            await Task.Run(() =>
            {
                RepairOrderService.EditRepairOrder(ro);
            });
        }
        else
        {
            await Task.Run(() =>
            {
                RepairOrderService.CreateRepairOrder(ro);
            });
        }
        this.isAdd = false;
        await LoadData();
    }

這是我的數據訪問層 class 中拋出錯誤的方法。

//Get all repair order details as a list
        public List<RepairOrder> GetAllRepairOrders()
        {
            try
            {
                return db.RepairOrder.ToList();
            }
            catch
            {
                throw;               
            }
        }

問題開始后,我使 LoadData() 方法異步。 誰能看到我錯過了什么?

**** 更新 ******** 我更改了“services.AddSingleton();” 到“services.AddTransient();” 它似乎正在工作。 我需要深入研究並嘗試確定這是否是我一開始就應該這樣做的方式!

正如錯誤所提到的,這里正在發生的事情是,當您的方法嘗試使用該上下文時,其他線程已經在使用該上下文。

將注冊更改為Transient是可行的,因為實例不再共享了……每次獲取它,它將是一個新實例……這有一些缺點,例如,如果您嘗試“加入”兩個“ IQueriable”它將失敗...內存消耗也應該上升...

現在,對於您的問題,您必須調試代碼流,因為顯然,當您的代碼輸入LoadData方法時,先前啟動的操作正在后台運行。 因此,“ Task.Run”實際上與錯誤無關...如果刪除它,您應該得到相同的錯誤...

您可以用來驗證此假設的操作是在加載數據之前添加了大約一秒或兩秒的延遲(等待Task.Delay(2000);)...這應該足以允許其他操作完成,從而釋放你的方法

這里有多個問題。

首先,使用異步。 您到處都在await Task.Run() ,這僅是有用的。 沒有Task.Run()更好地等待異步Db操作(FindAsync,ToListAsync)。

第二,服務的生命周期管理。 Blazor尚未執行AddScoped(某些啟動/身份項目除外)。

因此請注意,當您以正常方式(例如,在MVC應用程序中)注入該db時,它不會被釋放。 每個客戶都有自己的DbContext。 在他們的會議期間。

這不一定是問題,但是您應該格外小心,避免使用Changetracking。 也許自己管理Db上下文。

我會寫:

public async Task<List<RepairOrder>> GetAllRepairOrders()
{
     return await db.RepairOrder
       .AsNoTracking()   // tracking is expensive, only do it whne needed
       .ToListAsync();   // or maybe ToArrayAsync
}

然后在LoadData()中

_repairOrders = await RepairOrderService.GetAllRepairOrders();

這是Blazor服務器端,對嗎?

在服務器端Blazor中,添加到DI容器的所有對象的作用域應為“ 作用域 ”。 對象的生存期跨度到連接的生存期。 當您將一個對象添加為Singleton時,其生存期就是應用程序的持續時間。 這就是為什么都不要將任何對象添加為Singleton的原因。

我建議您不要使用Task.Run。 您的應用程序非常基礎,如果您遵循上述步驟,它將可以正常工作。

我建議您使用列表而不是數組來保存數據。

暫無
暫無

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

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