2 回答

TA貢獻1802條經驗 獲得超6個贊
當直接從數據庫提供 IEnumerable 時,控制器如何工作?
(我假設你的意思是直接從你的IEnumerable返回一個未執行的)IQueryableDbContext
他們不會,你也不應該- 這是因為未執行的IQueryable數據并不代表已加載的數據 - 當它執行時,它只能從打開的數據庫連接加載數據 - 這需要一個活動且有效的DbContext.
...所以如果 被DbContext處置,則IQueryable無法執行。
如果您DbContext在控制器內部創建操作并IQueryable在視圖中渲染或在ObjectResponse(對于 Web API)中返回它,那么它總是會失敗:
public IActionResult GetPeople()
{
// WARNING: NEVER DO THIS!
using( MyDbContext db = new MyDbContext( GetConnectionString() ) )
{
return this.Ok( db.People.Where( p => p.Name == "John Smith" ) );
// or:
return this.View( model: db.People.Where( p => p.Name == "John Smith" ) );
}
}
請記住,.Ok()andthis.View()不會觸發視圖的評估或向客戶端發送對象響應 - 相反,它會導致控制器操作首先結束,然后將數據傳遞到 ASP.NET 管道中的下一步(即視圖) 。請記住:視圖在控制器操作完成后執行。
如果您使用依賴注入在控制器中擁有一個現成的實例DbContext,那么結果就不太可預測:IQueryable在操作方法返回后仍然可以對 進行評估,因為DbContext直到控制器被處置之后才會被處置,通常是在視圖已呈現,但是您仍然不應該這樣做,因為您IQueryable仍然可能會傳遞到某個比您的 Controller 類的生命周期更長的進程,這會導致失敗。您還應該避免它,因為視圖被設計為快速同步渲染 - 外部數據庫或 IO 調用會破壞該設計。
(無論如何,您都不應該使用實體框架實體對象作為根 ViewModel,但這是另一個討論)。
如果您總是使用操作async(DbContext例如ToListAsync(),ToDictionaryAsync等 - 因為它們分別返回 aTask<List<T>>或TaskDictionary<TKey,TValue>>- 這需要一個await編譯器默認情況下會阻止您在視圖或對象結果中執行的操作,則可以避免這種習慣(您可以await在視圖中使用,但這是不可取的,需要在某處設置一些設置)。
簡而言之,始終這樣做:
public async Task<IActionResult> GetPeople()
{
using( MyDbContext db = new MyDbContext( GetConnectionString() ) )
{
List<Person> list = await db.People
.Where( p => p.Name == "John Smith" )
.ToListAsync();
// WebAPI:
return this.Ok( list ); // returning an evaluated list, loaded into memory. (Make sure Lazy Navigation Properties are disabled too)
// MVC:
PeopleListViewModel vm = new PeopleListViewModel(); // in MVC always use a custom class for root view-models so you're not accepting nor returning Entity Framework entity types directly
vm.List = list;
return this.View( vm );
}
}

TA貢獻1995條經驗 獲得超2個贊
您正在返回一個由 mvc 框架執行的任務;
當你等待一個任務時,你就開始(異步)運行它,然后獲取結果并將其交給 mvc 框架;
您將返回一個由 mvc 框架執行的枚舉器。
我會選擇選項#2,因為您確切知道數據庫查詢何時執行。由于您要返回任務并正確使用 async 和 wait 關鍵字,因此框架將盡可能多地保持線程繁忙,從而利用應用程序的吞吐量。
- 2 回答
- 0 關注
- 193 瀏覽
添加回答
舉報