entity framework中怎麼通過lambda表達式生成sql語句的?

假設用下面方法查出年齡大於18歲的用戶:

List& list=db.Set&().Where(x=&>x.age&>18).ToList();

、、

保存的時候通過反射找到user對象的屬性,並對應到資料庫欄位進行保存。這個很好理解,但是上面的用法其實只是傳入了一個方法。

光光通過這麼一句,EF內部是怎麼生成sql語句的呢?


Set返回的是IQuerable。然後你Where的時候,lambda表達式不是一個函數,而是一個Expression&<函數&>,C#編譯器會把這段代碼的語法樹在運行時直接交給IQuerable。所以IQuerable自然就知道你Where了,也知道你Where了什麼。但是ToList是要給結果的,IQuerable的ToList就會把之前的Where翻譯成SQL,然後提交上去,等結果回來了,搞成列表給你。


如 @vczh 所說,lambda表達式不是一個函數,而是一個Expression&<&>

Expression firstArg = Expression.Constant(2);
Expression secondArg = Expression.Constant(3);
Expression add = Expression.Add(firstArg, secondArg);
Console.WriteLine(add);

把以上代碼構建為以下表達式樹:

將表達式樹編譯為委託:

Expression firstArg = Expression.Constant(2);
Expression secondArg = Expression.Constant(3);
Expression add = Expression.Add(firstArg, secondArg);
Func& compiled = Expression.Lambda&&>(add).Compile();
Console.WriteLine(compiled());

從LINQ to Objects和LINQ to SQL生成SQL的方式略有不同:

註:圖來自 @vczh 推薦的 Csharp in Depth.3rd


在底層,會把拉姆達樹分成左右兩邊,然後遞歸解析,得到最後條件各種ifelse拼字元串。對於相同條件的語句當然會進行緩存。


微軟給了一個叫做expressionvisitor的類 具體用法是訪問者模式 如果你覺得自己解析表達式樹太累你可以用這個類 然後自己寫linq to sql這種將表達式翻譯成 sql的東西

我自己就用這種東西寫了個c#表達式翻譯成js的小東西

-------混割線-------

in case有人想看看c#表達式如何轉成JS 貼上git的地址

xboxeer/MyMVCExtension · GitHub ,裡面在MVCExtension裡面有個displaywhen的擴展方法 用表達式樹講C#表達式翻譯成了JS,自動將model屬性映射成前端的dom element, 不過僅支持簡單的表達式 複雜的元素不支持 字元串類型的也暫時不支持 有興趣的可以研究下如何支持字元串以及複雜元素

基本思路就是將翻譯後的js作為自定義的html attribute放到html element中,前端寫一個js去控制並利用eval去執行這段js 執行結果決定是否顯示dom element


大概是這麼做的:

具體要看文檔:SQL Generation


.net 上 lambda表達式有兩種表現形式:

1.題主說的「方法」,或者叫匿名委託,總之跟別的語言上的 lambda大差不差.

2.表達式樹,正如 輪子 哥講的,ef linq相關語句,編譯時變成了 expression,調用 tolist 遍歷 表達式樹,拼接出 sql,之後就是 ado.net 操作,結果映射填充回 set類型對象。

題外話,IQuerable 類型是個神奇的東西,他和 expression 是一對好基友~


前幾天看到篇文章

http://mp.weixin.qq.com/s?__biz=MzI4OTA3Mjc1MA==mid=401290739idx=1sn=bf7d2930963e898fe47acb5f169dfc68scene=0#wechat_redirect


推薦閱讀:

UWP應用為什麼比桌面應用要佔用相對較多的資源?
負責前後端開發,為什麼要學 C 語言?
為什麼Leetcode中C#運行速度比python還慢?
如何在C#中實現返回類型由參數決定的函數?

TAG:NET | C# | ORM | Lambda表達式 | EntityFramework |