<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          推薦必讀:EF Core 開發(fā)實踐規(guī)范

          共 7284字,需瀏覽 15分鐘

           ·

          2021-05-20 21:35




          嚴(yán)重問題

          客戶端求值


          • 如where條件包含的GetValueOrDefault()不能被翻譯成sql語句


          • 不規(guī)范代碼段例子


          public async Task<List<Person>> GetPersonsAsync()
          {
          var results = await _context.Person
          .Where(p => p.State.GetValueOrDefault() == 1)
          .ToListAsync()
          return results;
          }


          客戶端與服務(wù)器評估


          作為一般規(guī)則,Entity Framework Core 會嘗試盡可能全面地評估服務(wù)器上的查詢。EF Core 將查詢的一部分轉(zhuǎn)換為可在客戶端評估的參數(shù)。系統(tǒng)將查詢的其余部分(及生成的參數(shù))提供給數(shù)據(jù)庫提供程序,以確定要在服務(wù)器上評估的等效數(shù)據(jù)庫查詢。EF Core 支持在頂級投影中進行部分客戶端評估(基本上為最后一次調(diào)用 Select())。如果查詢中的頂級投影無法轉(zhuǎn)換為服務(wù)器,EF Core 將從服務(wù)器中提取任何所需的數(shù)據(jù),并在客戶端上評估查詢的其余部分。如果 EF Core 在頂級投影之外的任何位置檢測到不能轉(zhuǎn)換為服務(wù)器的表達式,則會引發(fā)運行時異常。請參閱查詢工作原理,了解 EF Core 如何確定哪些表達式無法轉(zhuǎn)換為服務(wù)器。


          在 3.0 版之前,Entity Framework Core 支持在查詢中的任何位置進行客戶端評估。


          頂級投影中的客戶端評估


          在下面的示例中,一個輔助方法用于標(biāo)準(zhǔn)化從 SQL Server 數(shù)據(jù)庫中返回的博客的 URL。由于 SQL Server 提供程序不了解此方法的實現(xiàn)方式,因此無法將其轉(zhuǎn)換為 SQL。查詢的所有其余部分是在數(shù)據(jù)庫中評估的,但通過此方法傳遞返回的 URL 卻是在客戶端上完成。


          var blogs = context.Blogs
          .OrderByDescending(blog => blog.Rating)
          .Select(blog => new{
          Id = blog.BlogId,
          Url = StandardizeUrl(blog.Url)
          })
          .ToList();
          public static string StandardizeUrl(string url)
          {
          url = url.ToLower();
          if (!url.StartsWith("http://"))
          {
          url = string.Concat("http://", url);
          }
          return url;
          }


          不支持的客戶端評估


          盡管客戶端評估非常有用,但有時會減弱性能。請看以下查詢,其中的 where 篩選器現(xiàn)已使用輔助方法。由于數(shù)據(jù)庫中不能應(yīng)用篩選器,因此需要將所有數(shù)據(jù)提取到內(nèi)存中,以便在客戶端上應(yīng)用篩選器。根據(jù)服務(wù)器上的篩選器和數(shù)據(jù)量,客戶端評估可能會減弱性能。因此 Entity Framework Core 會阻止此類客戶端評估,并引發(fā)運行時異常。


          var blogs = context.Blogs
          .Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
          .ToList();


          顯式客戶端評估


          在某些情況下,可能需要以顯式方式強制進行客戶端評估,如下所示


          由于數(shù)據(jù)量小,因此在進行客戶端評估時才不會大幅減弱性能。


          所用的 LINQ 運算符不會進行任何服務(wù)器端轉(zhuǎn)換。


          在這種情況下,通過調(diào)用 AsEnumerable 或 ToList 等方法(若為異步,則調(diào)用 AsAsyncEnumerable 或 ToListAsync),以顯式方式選擇進行客戶端評估。使用 AsEnumerable 將對結(jié)果進行流式傳輸,但使用 ToList 將通過創(chuàng)建列表來進行緩沖,因此也會占用額外的內(nèi)存。但如果枚舉多次,則將結(jié)果存儲到列表中可以帶來更大的幫助,因為只有一個對數(shù)據(jù)庫的查詢。根據(jù)具體的使用情況,你應(yīng)該評估哪種方法更適合。


          var blogs = context.Blogs
          .AsEnumerable()
          .Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
          .ToList();


          客戶端評估中潛在的內(nèi)存泄漏


          由于查詢轉(zhuǎn)換和編譯的開銷高昂,因此 EF Core 會緩存已編譯的查詢計劃。緩存的委托在對頂級投影進行客戶端評估時可能會使用客戶端代碼。


          EF Core 為樹型結(jié)構(gòu)中客戶端評估的部分生成參數(shù),并通過替換參數(shù)值重用查詢計劃。但表達式樹中的某些常數(shù)無法轉(zhuǎn)換為參數(shù)。如果緩存的委托包含此類常數(shù),則無法將這些對象垃圾回收,因為它們?nèi)员灰谩?/span>


          如果此類對象包含 DbContext 或其中的其他服務(wù),則會導(dǎo)致應(yīng)用的內(nèi)存使用量逐漸增多。此行為通常是內(nèi)存泄漏的標(biāo)志。只要遇到的常數(shù)為不能使用當(dāng)前數(shù)據(jù)庫提供程序映射的類型,EF Core 就會引發(fā)異常。常見原因及其解決方案如下所示:


          • 使用實例方法:在客戶端投影中使用實例方法時,表達式樹包含實例的常數(shù)。如果你的方法不使用該實例中的任何數(shù)據(jù),請考慮將該方法設(shè)為靜態(tài)方法。如果需要方法主體中的實例數(shù)據(jù),則將特定數(shù)據(jù)作為實參傳遞給方法。


          • 將常數(shù)實參傳遞給方法:這種情況通常是由于在客戶端方法的實參中使用 this 引起的。請考慮將實參拆分為多個標(biāo)量實參,可由數(shù)據(jù)庫提供程序進行映射。


          • 其他常數(shù):如果在任何其他情況下都出現(xiàn)常數(shù),則可以評估在處理過程中是否需要該常數(shù)。如果必須具有常數(shù),或者如果無法使用上述情況中的解決方案,則創(chuàng)建本地變量來存儲值,并在查詢中使用局部變量。EF Core 會將局部變量轉(zhuǎn)換為形參。


          建議解決


          無用追蹤


          • 無須追蹤的數(shù)據(jù)沒有加AsNoTracking


          跟蹤與非跟蹤查詢


          跟蹤行為決定了 Entity Framework Core 是否將有關(guān)實體實例的信息保留在其更改跟蹤器中。如果已跟蹤某個實體,則該實體中檢測到的任何更改都會在 SaveChanges() 期間永久保存到數(shù)據(jù)庫。EF Core 還將修復(fù)跟蹤查詢結(jié)果中的實體與更改跟蹤器中的實體之間的導(dǎo)航屬性。


          從不跟蹤無鍵實體類型。無論在何處提到實體類型,它都是指定義了鍵的實體類型。


          跟蹤查詢


          返回實體類型的查詢是默認(rèn)會被跟蹤的。這表示可以更改這些實體實例,然后通過 SaveChanges() 持久化這些更改。在以下示例中,將檢測到對博客評分所做的更改,并在 SaveChanges() 期間將這些更改持久化到數(shù)據(jù)庫中。


          var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
          blog.Rating = 5;
          context.SaveChanges();


          非跟蹤查詢


          在只讀方案中使用結(jié)果時,非跟蹤查詢十分有用。可以更快速地執(zhí)行非跟蹤查詢,因為無需設(shè)置更改跟蹤信息。如果不需要更新從數(shù)據(jù)庫中檢索到的實體,則應(yīng)使用非跟蹤查詢。可以將單個查詢替換為非跟蹤查詢。


          var blogs = context.Blogs
          .AsNoTracking()
          .ToList();


          還可以在上下文實例級別更改默認(rèn)跟蹤行為:


          context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
          var blogs = context.Blogs.ToList();


          標(biāo)識解析


          由于跟蹤查詢使用更改跟蹤器,因此 EF Core 將在跟蹤查詢中執(zhí)行標(biāo)識解析。當(dāng)具體化實體時,如果 EF Core 已被跟蹤,則會從更改跟蹤器返回相同的實體實例。如果結(jié)果中多次包含相同的實體,則每次會返回相同的實例。


          非跟蹤查詢不會使用更改跟蹤器,也不會執(zhí)行標(biāo)識解析。因此會返回實體的新實例,即使結(jié)果中多次包含相同的實體也是如此。此行為與 EF Core 3.0 之前的版本中的行為有所不同,請參閱早期版本。


          跟蹤和自定義投影


          即使查詢的結(jié)果類型不是實體類型,默認(rèn)情況下 EF Core 也會跟蹤結(jié)果中包含的實體類型。在以下返回匿名類型的查詢中,結(jié)果集中的 Blog 實例會被跟蹤。


          var blog = context.Blogs
          .Select(b =>
          new
          {
          Blog = b,
          PostCount = b.Posts.Count()
          });


          如果結(jié)果集包含來自 LINQ 組合的實體類型,EF Core 將跟蹤它們。


          var blog = context.Blogs
          .Select(b =>
          new
          {
          Blog = b,
          Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault()
          });


          如果結(jié)果集不包含任何實體類型,則不會執(zhí)行跟蹤。在以下查詢中,我們返回匿名類型(具有實體中的某些值,但沒有實際實體類型的實例)。查詢中沒有任何被跟蹤的實體。


          var blog = context.Blogs
          .Select(b =>
          new
          {
          Id = b.BlogId,
          Url = b.Url
          });


          EF Core 支持執(zhí)行頂級投影中的客戶端評估。如果 EF Core 具體化實體實例以進行客戶端評估,則會跟蹤該實體實例。


          此處,由于我們要將 blog 實體傳遞到客戶端方法 StandardizeURL,因此 EF Core 也會跟蹤博客實例。


          var blogs = context.Blogs
          .OrderByDescending(blog => blog.Rating)
          .Select(blog => new
          {
          Id = blog.BlogId,
          Url = StandardizeUrl(blog)
          })
          .ToList();
          public static string StandardizeUrl(Blog blog)
          {
          var url = blog.Url.ToLower();
          if (!url.StartsWith("http://"))
          {
          url = string.Concat("http://", url);
          }
          return url;
          }


          EF Core 不會跟蹤結(jié)果中包含的無鍵實體實例。但 EF Core 會根據(jù)上述規(guī)則跟蹤帶有鍵的實體類型的所有其他實例。


          在 EF Core 3.0 之前,某些上述規(guī)則的工作方式有所不同。有關(guān)詳細信息,請參閱早期版本。


          沒有使用異步方法


          • 沒有優(yōu)先使用異步方法


          • 不規(guī)范代碼段例子


          public async Task<int> AddPersons(IEnumerable<Person> persons)
          {
          this._context.Person.AddRange(persons);
          return await this._context.SaveChangesAsync();
          }


          異步查詢


          當(dāng)在數(shù)據(jù)庫中執(zhí)行查詢時,異步查詢可避免阻止線程。異步查詢對于在胖客戶端應(yīng)用程序中保持響應(yīng)式 UI 非常重要。異步查詢還可以增加 Web 應(yīng)用程序中的吞吐量,即通過釋放線程,以處理 Web 應(yīng)用程序中的其他請求。有關(guān)詳細信息,請參閱使用 C# 異步編程。


          EF Core 不支持在同一上下文實例上運行多個并行操作。應(yīng)始終等待操作完成,然后再開始下一個操作。這通常是通過在每個異步操作上使用 await 關(guān)鍵字完成的。


          Entity Framework Core 提供一組類似于 LINQ 方法的異步擴展方法,用于執(zhí)行查詢并返回結(jié)果。示例包括 ToListAsync()、ToArrayAsync()、SingleAsync()。某些 LINQ 運算符(如 Where(...) 或 OrderBy(...))沒有對應(yīng)的異步版本,因為這些方法僅用于構(gòu)建 LINQ 表達式樹,而不會導(dǎo)致在數(shù)據(jù)庫中執(zhí)行查詢。


          EF Core 異步擴展方法在 Microsoft.EntityFrameworkCore 命名空間中定義 。必須導(dǎo)入此命名空間才能使這些方法可用。


          public async Task<List<Blog>> GetBlogsAsync()
          {
          using (var context = new BloggingContext())
          {
          return await context.Blogs.ToListAsync();
          }
          }


          事務(wù)濫用


          • 沒必要使用事務(wù)的場景使用事務(wù)


          • 不規(guī)范代碼段例子


          public async Task<bool> UpdatePersonInfo(List<Person> persons, List<Address> addresses)
          {
          using (var transaction = _dbContext.Database.BeginTransaction(IsolationLevel.ReadCommitted))
          {
          try
          {
          _dbContext.Person.UpdateRange(persons);
          await _dbContext.SaveChangesAsync();
          _dbContext.Address.UpdateRange(addresses);
          await _dbContext.SaveChangesAsync();
          transaction.Commit();
          return true;
          }
          catch (Exception ex)
          {
          transaction.Rollback();
          throw new InternalServerErrorException($"更新失敗,ErrorMessage:{ex.Message}
          InnerException:{ex.InnerException}"
          , ex);
          }
          }
          }


          使用事務(wù)


          事務(wù)允許以原子方式處理多個數(shù)據(jù)庫操作。如果已提交事務(wù),則所有操作都會成功應(yīng)用到數(shù)據(jù)庫。如果已回滾事務(wù),則所有操作都不會應(yīng)用到數(shù)據(jù)庫。


          默認(rèn)事務(wù)行為


          默認(rèn)情況下,如果數(shù)據(jù)庫提供程序支持事務(wù),則會在單次調(diào)用 SaveChanges() 時將所有更改都將應(yīng)用到事務(wù)中。如果其中有任何更改失敗,則會回滾事務(wù)且所有更改都不會應(yīng)用到數(shù)據(jù)庫。這意味著,SaveChanges() 可保證要么完全成功,要么在出現(xiàn)錯誤時不修改數(shù)據(jù)庫。


          對于大多數(shù)應(yīng)用程序,此默認(rèn)行為已足夠。除非應(yīng)用程序確有需求,否則不應(yīng)手動控制事務(wù)。


          控制事務(wù)


          可以使用 DbContext.Database API 開始、提交和回滾事務(wù)。以下示例顯示了在單個事務(wù)中執(zhí)行的兩個 SaveChanges() 操作以及 一個LINQ 查詢。


          并非所有數(shù)據(jù)庫提供程序都支持事務(wù)。調(diào)用事務(wù) API 時,某些提供程序可能會引發(fā)異常或不執(zhí)行任何操作。


          規(guī)范參考


          • 數(shù)據(jù)追蹤參考規(guī)范

            https://docs.microsoft.com/zh-cn/ef/core/querying/tracking


          • 客戶端求值參考規(guī)范

            https://docs.microsoft.com/zh-cn/ef/core/querying/client-eval


          • 異步查詢參考規(guī)范

            https://docs.microsoft.com/zh-cn/ef/core/querying/async


          • 加載相關(guān)數(shù)據(jù)參考規(guī)范

            https://docs.microsoft.com/zh-cn/ef/core/querying/related-data


          • 事務(wù)使用參考規(guī)范

            https://docs.microsoft.com/zh-cn/ef/core/saving/transactions


          github:https://github.com/cailin0630

          回復(fù) 【關(guān)閉】學(xué)關(guān)
          回復(fù) 【實戰(zhàn)】獲取20套實戰(zhàn)源碼
          回復(fù) 【福利】獲取最新微信支付有獎勵
          回復(fù) 【被刪】學(xué)
          回復(fù) 【訪客】學(xué)
          回復(fù) 【卡通】學(xué)制作微信卡通頭像
          回復(fù) 【python】學(xué)微獲取全套0基礎(chǔ)Python知識手冊
          回復(fù) 【2019】獲取2019 .NET 開發(fā)者峰會資料PPT

          又來一個神奇的網(wǎng)站!


          谷歌靈魂插件,98%的程序員都好評!


          瀏覽 89
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  激情黄色免费视频 | 手机在线免费AV | 亚洲无码一卡二卡 | 俺去久久| 97成人午夜福利 |