亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

直接從數據庫返回 IEnumerable 或之前使用 ToListAsync

直接從數據庫返回 IEnumerable 或之前使用 ToListAsync

C#
肥皂起泡泡 2023-08-13 13:57:51
當直接從數據庫提供 IEnumerable 時,控制器如何工作?哪個代碼更正確、更優化?假設數據庫非常慢并且正在進行其他操作。這個示例非常簡單,因此執行時間可能沒有足夠的差異,但我正在嘗試學習最佳實踐。#1public Task<Application[]> Find(Expression<Func<Application, bool>> predicate){    return DatabaseContext.Applications        .Where(predicate)        .ToArrayAsync();}...public Task<Application[]> Find(...){    return ApplicationService.Find(...);}#2public Task<List<Application>> Find(Expression<Func<Application, bool>> predicate){    return DatabaseContext.Applications        .Where(predicate)        .ToListAsync();}...public async Task<IActionResult> Find(...){    var applications = await ApplicationService.Find(...)    return Ok(applications);}#3public IEnumerable<Application> Find(Expression<Func<Application, bool>> predicate){    return DatabaseContext.Applications;}...public IActionResult<IEnumerable<Application>> Find(...){    var applications = ApplicationService.Find(...);    return Ok(applications);}
查看完整描述

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 );

    }

}


查看完整回答
反對 回復 2023-08-13
?
拉風的咖菲貓

TA貢獻1995條經驗 獲得超2個贊

  1. 您正在返回一個由 mvc 框架執行的任務;

  2. 當你等待一個任務時,你就開始(異步)運行它,然后獲取結果并將其交給 mvc 框架;

  3. 您將返回一個由 mvc 框架執行的枚舉器。

我會選擇選項#2,因為您確切知道數據庫查詢何時執行。由于您要返回任務并正確使用 async 和 wait 關鍵字,因此框架將盡可能多地保持線程繁忙,從而利用應用程序的吞吐量。


查看完整回答
反對 回復 2023-08-13
  • 2 回答
  • 0 關注
  • 193 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號