最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#表達式中的動態(tài)查詢詳解【譯】

 更新時間:2021年01月05日 12:03:25   作者:michael  
這篇文章主要給大家介紹了關(guān)于C#表達式中動態(tài)查詢的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

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

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

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

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

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

DbSet<Student> students = context.Students;
var billie = await students.Where(s => s.StudentName == "Billie").ToListAsync();

執(zhí)行時,實體框架會產(chǎn)生以下SQL查詢:

SQL:SELECT
 [Extent1].[StudentID] AS [StudentID],
 [Extent1].[StudentName] AS [StudentName],
 [Extent1].[DateOfBirth] AS [DateOfBirth],
 FROM [dbo].[Students] AS [Extent1]
 WHERE N'Billie' = [Extent1].[StudentName]

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

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

在最后一個示例中,SQL查詢使所有學生進入流程,并將其映射到常規(guī)集合。不同之處在于,在第一段代碼中,lambda是一個Expression<Func<Student, bool>>,它允許實體框架將其添加到SQL查詢中。在第二段代碼中,lambda是a Func<Student, bool>,因此將Where執(zhí)行操作符之前的所有操作并將其轉(zhuǎn)換為常規(guī)IEnumerable集合,然后執(zhí)行其余的查詢。

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

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

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

C#表達式樹

在第一段代碼中,類型s => s.StudentName == "Billie"為Expression<Func<Student, bool>>。這表示生成樹的表達式樹Func<Student, bool>。該Where子句接受這種類型的參數(shù),因為aDbSet<TEntity>實現(xiàn)了IQueryable<T>接口,這要求它與表達式樹配合使用。相反,常規(guī)集合(如數(shù)組或a List<T>)IEnumerable意味著它將lambdas => s.StudentName == "Billie"用作常規(guī)函數(shù)。

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

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

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

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

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

IQueryable<Error> _errors;

public IEnumerable<Error> GetErrors(string propertyToFilter, string value)
{
 switch (propertyToFilter)
 {
  case "Username":
   return await _errors.Where(e=> e.Username == value).ToListAsync();
  case "Country":
   return await _errors.Where(e=> e.Country == value).ToListAsync();
  case "Version":
   return await _errors.Where(e=> e.Version == value).ToListAsync();
  // ...  
 }
}

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

通過動態(tài)查詢和表達式樹可以實現(xiàn)此功能的方法如下:

private async static Task<IEnumerable<Error>> GetErrors(string propertyToFilter, string value)
{
 var error = Expression.Parameter(typeof(Error));
 var memberAccess = Expression.PropertyOrField(error, propertyToFilter);
 var exprRight = Expression.Constant(value);
 var equalExpr = Expression.Equal(memberAccess, exprRight);
 Expression<Func<Error, bool>> lambda = Expression.Lambda<Func<Error, bool>>(equalExpr, error);

 return await _errors.Where(lambda).ToListAsync();
}

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

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

概要

回顧一下。這是本文中的一些關(guān)鍵點:

•常規(guī)函數(shù)/委托與表達式之間的區(qū)別在于,表達式可以用結(jié)構(gòu)化樹表示??梢暂p松地分析該樹以創(chuàng)建諸如數(shù)據(jù)庫查詢之類的東西。

•支持表達式的數(shù)據(jù)源實現(xiàn)該IQueryable接口。

•如果您無法使用表達式(以及使用常規(guī)方法或委托),則查詢將在服務器端而不在數(shù)據(jù)庫端,這對于性能而言將是可怕的。

•使用lambda(不帶主體)時,表達式是無縫創(chuàng)建的,因此這些年來您可能一直都在這樣做。

•您可以自己使用表達式樹來創(chuàng)建動態(tài)查詢。這在無法在編譯時僅在運行時構(gòu)建查詢的情況下很有用。

總結(jié)

到此這篇關(guān)于C#表達式中的動態(tài)查詢的文章就介紹到這了,更多相關(guān)C#表達式的動態(tài)查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

References

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

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

相關(guān)文章

  • C#加密解密類實例程序

    C#加密解密類實例程序

    這篇文章主要介紹了C#加密解密類實例程序,大家參考使用吧
    2013-12-12
  • C#中StringBuilder類的使用總結(jié)

    C#中StringBuilder類的使用總結(jié)

    本篇文章主要是對C#中StringBuilder類的使用方法進行了詳細的總結(jié)介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01
  • 通過特性(attribute)為枚舉添加更多信息示例

    通過特性(attribute)為枚舉添加更多信息示例

    這篇文章主要介紹了通過特性(Attribute)為枚舉添加更多的信息,大家參考使用吧
    2014-01-01
  • c#文件名/路徑處理方法示例

    c#文件名/路徑處理方法示例

    這篇文章主要介紹了c#文件名/路徑處理方法,大家寫代碼處理文件的時候會常用到
    2013-12-12
  • dotNet中的反射用法入門教程

    dotNet中的反射用法入門教程

    這篇文章主要介紹了dotNet中的反射用法,較為詳細的分析了.Net中關(guān)于反射的概念,使用方法與相關(guān)注意事項,需要的朋友可以參考下
    2016-02-02
  • 簡單學習C#中的泛型方法使用

    簡單學習C#中的泛型方法使用

    這篇文章主要介紹了C#中的泛型方法使用,需要的朋友可以參考下
    2016-02-02
  • LINQ操作符SelectMany的用法

    LINQ操作符SelectMany的用法

    這篇文章介紹了LINQ操作符SelectMany的用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • C#在PDF中繪制不同風格類型的文本方法實例

    C#在PDF中繪制不同風格類型的文本方法實例

    這篇文章主要給大家介紹了關(guān)于C#在PDF中繪制不同風格類型的文本的相關(guān)資料,文中通過圖文以及示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-07-07
  • C#加密解密文件小工具實現(xiàn)代碼

    C#加密解密文件小工具實現(xiàn)代碼

    一個文件夾加密小工具,該工具是操作文件夾名稱的方法實現(xiàn)文件夾的一般加密,文件夾中的文件(視頻、圖片等)都原封不動的保存在那里
    2012-05-05
  • 深入了解c# 設計模式之簡單工廠模式

    深入了解c# 設計模式之簡單工廠模式

    這篇文章主要介紹了c# 設計模式之簡單工廠模式的的相關(guān)資料,文中代碼非常詳細,幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06

最新評論

修水县| 光泽县| 灵璧县| 安吉县| 家居| 许昌市| 翁牛特旗| 托克逊县| 城口县| 鹿泉市| 明水县| 平和县| 西平县| 汝州市| 遂溪县| 铜鼓县| 太康县| 万安县| 常德市| 济宁市| 淮滨县| 邳州市| 福泉市| 通城县| 印江| 保康县| 乡宁县| 青海省| 远安县| 通道| 乌兰察布市| 蓝田县| 连江县| 岑巩县| 临西县| 石楼县| 兴城市| 镇赉县| 永春县| 开化县| 舟曲县|