成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C#表達式中的動態查詢

開發 后端
當您使用LINQ來處理數據庫時,這種體驗是一種神奇的體驗,對嗎?你把數據庫實體像一個普通的收集,使用Linq中像Where,Select或者 Take,這些簡單的使用就能讓代碼可用了。

當您使用LINQ來處理數據庫時,這種體驗是一種神奇的體驗,對嗎?你把數據庫實體像一個普通的收集,使用Linq中像Where,Select或者 Take,這些簡單的使用就能讓代碼可用了。

但是,讓我們考慮一下這里是如何通過動態查詢和表達式樹實現此功能的:幕后發生的事情。您編寫的LINQ查詢將轉換為SQL(或其他方式),并將該SQL查詢發送到數據庫。然后將數據庫的響應映射到C#對象。但是,如何完全轉換為SQL?

在本文中,您將看到諸如Entity Framework和MongoDB C#驅動程序之類的框架如何使用表達式樹進行轉換。您將看到如何親自使用表達式樹來構建動態查詢。這些查詢是您無法在編譯時創建的查詢,因為您將知道該查詢僅在運行時的外觀。

對可查詢樹和表達式樹進行揭秘

考慮以下使用Entity Framework 6的C#代碼:

  1. SQL:SELECT 
  2.     [Extent1].[StudentID] AS [StudentID], 
  3.     [Extent1].[StudentName] AS [StudentName], 
  4.     [Extent1].[DateOfBirth] AS [DateOfBirth], 
  5.     FROM [dbo].[Students] AS [Extent1] 
  6.     WHERE N'Billie' = [Extent1].[StudentName] 

請注意,WHERESQL查詢中有一個操作。那不是很明顯。如果SQL不包含WHERE,則所有學生都將從數據庫中帶走,并且篩選將在.NET進程中執行。實際上,以下代碼可以做到這一點:

  1. //BAD: 
  2. DbSet<Student> students = context.Students; 
  3. Func<Student, bool> predicate = s => s.StudentName == "Billie"
  4. var x = students.Where(predicate).ToList(); 

在最后一個示例中,SQL查詢使所有學生進入流程,并將其映射到常規集合。不同之處在于,在第一段代碼中,lambda是一個Expression

第二段代碼在性能,內存和網絡方面很糟糕。我們從網絡中獲取了許多對象,而不是僅從數據庫中獲取一個項目。然后,我們使用CPU將它們序列化為C#對象。并用完內存將它們存儲在進程的堆中。

因此,讓我們回到第一段代碼。如何await students.Where(s => s.StudentName == "Billie").ToListAsync()產生一個包含的SQL查詢WHERE N'Billie' = [Extent1].[StudentName]?

答案是表達樹。該代碼s => s.StudentName == "Billie"實際上是一個結構化查詢,可以通過編程將其分解為節點樹。在此示例中,有6個節點。最頂層的節點是lambda表達式。左側是lambda參數。在它的右邊是Equal表示表達式的lambda主體。實體框架具有遍歷這些表達式樹并構造SQL查詢的算法。其他數據源提供程序(如Mongo DB C#驅動程序)也會發生同樣的事情,除了它會構造一個MongoDB json查詢。

C#表達式樹

在第一段代碼中,類型s => s.StudentName == "Billie"為Expression

好的,但是我該如何利用它呢?

在大多數情況下,使用表達樹的人們就是在構建世界實體框架的人們。但是在某些特定情況下,它變得非常有用。這是我們最近在Ozcode[1](我的日常工作)中遇到的一個用例:

我們想在名為Error的數據庫實體上創建動態服務器端過濾。該實體具有許多屬性,我們希望允許用戶對其進行過濾。因此過濾應根據被允許Username,Country,Version,或任何其他財產。這是我們需要實現的API:

  1. IQueryable<Error> _errors;  
  2. public IEnumerable<Error> GetErrors(string propertyToFilter, string value){ /*..*/}  

在這種情況下,propertyToFilter是的屬性Error。使用常規的LINQ,唯一的方法就是使用巨大的switch / case語句。有點像這樣:

  1. IQueryable<Error> _errors; 
  2.  
  3. public IEnumerable<Error> GetErrors(string propertyToFilter, string value) 
  4.     switch (propertyToFilter) 
  5.     { 
  6.         case "Username"
  7.             return await _errors.Where(e=> e.Username == value).ToListAsync(); 
  8.         case "Country"
  9.             return await _errors.Where(e=> e.Country == value).ToListAsync(); 
  10.         case "Version"
  11.             return await _errors.Where(e=> e.Version == value).ToListAsync(); 
  12.         // ...         
  13.     } 

您可能會同意這不是理想的選擇。除了必須編寫所有這些東西之外,它還非常容易出現錯誤。如果添加了屬性怎么辦?如果重命名怎么辦?整個事情一團糟。

通過動態查詢和表達式樹可以實現此功能的方法如下:

  1. private async static Task<IEnumerable<Error>> GetErrors(string propertyToFilter, string value) 
  2.     var error = Expression.Parameter(typeof(Error)); 
  3.     var memberAccess = Expression.PropertyOrField(error, propertyToFilter); 
  4.     var exprRight = Expression.Constant(value); 
  5.     var equalExpr = Expression.Equal(memberAccess, exprRight); 
  6.     Expression<Func<Error, bool>> lambda = Expression.Lambda<Func<Error, bool>>(equalExpr, error); 
  7.  
  8.     return await _errors.Where(lambda).ToListAsync(); 

這里的每一行代碼代表表達式樹中的一個節點。它們共同構成了最高節點-lambda。然后,可以在LINQ中使用動態表達式,并生成服務器端SQL查詢。我認為很好。

解決此問題的另一種方法是構建自定義SQL查詢字符串。在Ozcode中,我們使用的是MongoDB,因此SQL不適合使用,但我們可以創建一個自定義的MongoDB JSON查詢字符串。也不是太難,但是我認為表達式樹方法更加靈活和可靠。一方面,您可以將其放在LINQ中并與其他LINQ運算符組合。此外,當有諸如Entity Framework之類的經過測試的框架可以為您執行此操作時,為什么還要編寫自己的查詢。

概要

回顧一下。這是本文中的一些關鍵點:

  • 常規函數/委托與表達式之間的區別在于,表達式可以用結構化樹表示??梢暂p松地分析該樹以創建諸如數據庫查詢之類的東西。
  • 支持表達式的數據源實現該IQueryable接口。
  • 如果您無法使用表達式(以及使用常規方法或委托),則查詢將在服務器端而不在數據庫端,這對于性能而言將是可怕的。
  • 使用lambda(不帶主體)時,表達式是無縫創建的,因此這些年來您可能一直都在這樣做。
  • 您可以自己使用表達式樹來創建動態查詢。這在無法在編譯時僅在運行時構建查詢的情況下很有用。

References

[1] Ozcode: https://oz-code.com 

[2]: https://www.mediavine.com/

責任編輯:武曉燕 來源: DotNET技術圈
相關推薦

2009-09-14 13:57:20

C# Lambda表達Lambda表達式

2024-03-25 13:46:12

C#Lambda編程

2009-07-09 09:51:07

Lambda表達式C#

2011-07-06 11:04:42

C#正則表達式

2011-04-25 08:44:34

C#正則表達式

2009-08-27 09:44:59

C# Lambda表達

2009-08-07 15:41:39

C#正規表達式

2009-04-09 09:19:25

C#規則表達式.NET

2010-10-19 10:03:02

Lambda表達式

2009-08-17 13:56:28

C#正則表達式入門

2009-08-27 09:57:50

C# Lambda表達

2009-08-07 15:16:10

C#正則表達式

2009-08-26 16:17:23

C# Lambda表達

2009-08-03 17:27:14

C#正則表達式

2024-05-15 08:09:23

2009-08-11 13:00:41

C#正則表達式

2009-08-13 15:24:27

C#正則表達式

2009-08-11 16:03:13

C#運算符

2024-12-16 07:33:45

C#正則表達式

2021-08-31 07:19:41

Lambda表達式C#
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品四区 | 伊人精品久久久久77777 | 午夜视频一区二区 | 亚洲乱码一区二区三区在线观看 | 中文字幕色站 | 国产伦一区二区三区视频 | 香蕉av免费| 精品一区二区三区在线观看国产 | 成人一区二 | 18成人在线观看 | 国产精品99久久久久久动医院 | 一级黄色片毛片 | 国产精品久久久久无码av | 久艹av | 丝袜久久| 成人福利影院 | 麻豆视频在线免费观看 | 国产精品免费观看 | 一区二区中文 | 国产精品久久久99 | 99re6在线视频精品免费 | 午夜精品一区二区三区在线视频 | 天天干天天玩天天操 | 狠狠操你| 一区二区视频 | 在线观看国产视频 | 精品视频一区二区三区 | 久热9| 日本中文字幕在线观看 | 国产免费黄网 | 欧美精品在欧美一区二区 | a级片播放 | 天天干夜夜操 | 亚洲国产成人av好男人在线观看 | 免费黄色片在线观看 | 国产不卡视频 | www.免费看片.com | 久久久精品网 | 99精品视频在线 | 亚洲风情在线观看 | 欧美成人精品一区二区三区 |