我們先來一段最基本的 LINQ to SQL 使用類似 T-SQL 的 INNER JOIN 資料查詢語法:

from c in Categories
from o in c.Products
select new { c.CategoryName, o.ProductID, o.ProductName }

我們可以從上述 LINQ 語法上就知道有兩個資料來源(因為有兩個 from 子句),而第二個 from 使用的是第一個 from 資料來源的關連屬性,因此產生 JOIN 需求,這段 LINQ 語法所產生的 T-SQL 語句如下:

SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
FROM [Categories] AS [t0], [Products] AS [t1]
WHERE [t1].[CategoryID] = [t0].[CategoryID]

接著我們來看看另一個 INNER JOIN 的資料查詢語法,我們使用語意更為明確的 join 子句:

from c in Categories
join o in Products on c.CategoryID equals o.CategoryID
select new { c.CategoryName, o.ProductID, o.ProductName }

我們可以從上述 LINQ 語法上知道有一個 Categories 資料來源,並且 join 另一個 Products 資料來源,當中用這個兩個實體的其中一個 CategoryID 屬性進行 join 動作,這是一個非常明確的 join 語法,其語法與 T-SQL 的 join 語法非常相近,這段 LINQ 語法所產生的 T-SQL 語句如下:

SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]

這兩段 LINQ 語法所執行的結果資料一模一樣,不過產生的 T-SQL 不一樣,所以透過 LINQ to SQL 會自動將設定的 LINQ 語法產生出合適的 T-SQL 語法。不過,我們都知道資料庫查詢的 SQL 語法有很多調校的技巧,透過 LINQ to SQL 之後自然會變的不容易調校,所以針對某些 LINQ 語法還是有可能產生效能不彰的狀況需要自行處理。

舉個例子來說,以下 LINQ 語法除了 join 外還在 select 的地方有隱含的使用了另一個 JOIN 條件:

from c in Categories
join o in Products on c.CategoryID equals o.CategoryID
select new { o.Category.CategoryName ,o.ProductID, o.ProductName }

因此會產生出一個詭異且無效率的 T-SQL 語法如下,同時有 INNER JOIN 與 LEFT OUTER JOIN 的狀況:

SELECT [t2].[CategoryName], [t0].[ProductID], [t0].[ProductName]
FROM [Products] AS [t0]
INNER JOIN [Categories] AS [t1] ON [t0].[CategoryID] = ([t1].[CategoryID])
LEFT OUTER JOIN [Categories] AS [t2] ON [t2].[CategoryID] = [t0].[CategoryID]

這時我們修正 LINQ 語法如下:

from c in Categories
join o in Products on c.CategoryID equals o.CategoryID
select new { c.CategoryName, o.ProductID, o.ProductName }

這時就會產生預期的 T-SQL 語法:

SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]

雖然 LINQ 出現的目的就是希望你改用「物件」與「實體」的角度來思考資料的查詢方式,不過如果你能瞭解從 LINQ 轉換到 T-SQL 的過程將有助於你寫出更有效率的 LINQ 查詢語法。

瞭解 INNER JOIN 之後,我們再來看一個 T-SQL 中常見的 LEFT JOIN 語法的 LINQ 要如何撰寫:

from o in Products
select new { o.Category.CategoryName, o.ProductID, o.ProductName }

這段 LINQ 語法我們只取出一個 Products 資料來源,但是在 select 子句卻額外取得 Category 關連實體的資料,這個關連是「多對一」的關連,所以一個 Product 實體只會取得一個 Category 實體,所以轉換 T-SQL 之後你會發現 LEFT JOIN 的左邊就是 Products,而右邊就變成 Categories,其所產生的 T-SQL 語句如下:

SELECT [t1].[CategoryName], [t0].[ProductID], [t0].[ProductName]
FROM [Products] AS [t0]
LEFT OUTER JOIN [Categories] AS [t1] ON [t1].[CategoryID] = [t0].[CategoryID]

雖然你看到的是一個 LEFT JOIN 語法,不過這並不是我們常見的那種 JOIN 狀況,比較複雜的狀況是當我們左側的實體為 Categories 以及右側的實體為 Products 的狀況,這是「一對多」的關連,複雜度相對提高一些。

由於 INNER JOIN 是 交集(AND) 的概念,當兩個 JOIN 的實體都有資料時才有資料。而 LEFT JOIN 的概念卻是「左邊的資料全部都要有,即便右邊沒有資料也要以 null 代替」,因此我們的 LINQ to SQL 語法如下就要特別注意資料來源出現的順序性:

我們先重寫文章稍早出現的過的 INNER JOIN 語法如下:

from c in Categories
join o in Products on c.CategoryID equals o.CategoryID
select new { c.CategoryName, o.ProductName }

如果要改成 LEFT JOIN 語法,則必須修改成以下 LINQ 語法:

from c in Categories
join o in Products on c.CategoryID equals o.CategoryID into ps
from o in ps.DefaultIfEmpty()

select new { c.CategoryName, o.ProductName }

因為撰在 LINQ 撰寫 LEFT JOIN 時的觀念與 T-SQL 不太一樣,要用「物件」的角度比較能理解其語法所代表的意義,所以上述的語法可以這樣解釋:

取出 Categories 資料並放入 c 變數,接著再與 Products 做 JOIN 並將 JOIN 後的結果放入 ps 變數(注意:並非第二行的 o 變數),這時再宣告一個資料來源 o 其資料來自於「修改過的 ps 變數」,且修改的方式為 ps.DefaultIfEmpty(),意即代表若 ps ( 也就是 Products 經過 join 篩選後的資料 ) 無任何資料時,還是回傳一筆 Default 的資料(也就是預設的 null 資料)。

這一段 LINQ 所產生的 T-SQL 如下:

SELECT [t0].[CategoryName], [t1].[ProductName] AS [ProductName]
FROM [Categories] AS [t0]
LEFT OUTER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]

因此當你需要撰寫「多對一」關連情況下正確的使用 LINQ 查詢語法做 LEFT JOIN 就必須這樣來撰寫!

不過有一點必須注意,那就是當 o 取得的物件為 null 時,雖然 select 子句中的 o.ProductName 不會引發例外,而且會回傳 null,但是若你在 select 子句中設定 o.ProductID 的話,那就會引發例外,因為 null 並無法正確轉型成 Int32 型別,錯誤訊息是:InvalidOperationException - 無法將 Null 值指派給型別 System.Int32 的成員,該型別不可為 Null 值。

文章来源:http://blog.miniasp.com/post/2010/10/14/LINQ-to-SQL-Query-Tips-INNER-JOIN-and-LEFT-JOIN.aspx

关于Linq翻译Inner join ,Left join (本文为转载)的更多相关文章

  1. Linq中join & group join & left join 的用法

    Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报  分类: C#(14)  文章 ...

  2. Linq 多表连接查询join

    在查询语言中,通常需要使用联接操作.在 LINQ 中,可以通过 join 子句实现联接操作.join 子句可以将来自不同源序列,并且在对象模型中没有直接关系(数据库表之间没有关系)的元素相关联,唯一的 ...

  3. LINQ TO SQL 中的join(转帖)

    http://www.cnblogs.com/ASPNET2008/archive/2008/12/21/1358152.html join对于喜欢写SQL的朋友来说还是比较实用,也比较容易接受的东西 ...

  4. MySQL Left Join,Right Join

    魂屁,东西发这里了关于Left Join,Right Join的 在讲MySQL的Join语法前还是先回顾一下联结的语法,呵呵,其实连我自己都忘得差不多了,那就大家一起温习吧(如果内容有错误或有疑问, ...

  5. 浅谈SQL Server中的三种物理连接操作(HASH JOIN MERGE JOIN NESTED LOOP)

    简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...

  6. 左连接,右连接,内连接(left join ,right join,inner join)

    浅谈左连接,右连接,内连接(left join ,right join,inner join) 这个问题一直困扰着我,每次遇到就打擦边球,不正面应对.今天索性把这几个连接搞懂了,写下这篇博客, 让跟我 ...

  7. SQL语句中LEFT JOIN、JOIN、INNER JOIN、RIGHT JOIN的区别?

    w3school的一套sql教程: http://www.w3school.com.cn/sql/index.asp left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录.r ...

  8. join中级篇---------hash join & merge join & nested loop Join

    嵌套循环连接(Nested Loop Join) 循环嵌套连接是最基本的连接,正如其名所示那样,需要进行循环嵌套,嵌套循环是三种方式中唯一支持不等式连接的方式,这种连接方式的过程可以简单的用下图展示: ...

  9. Mysql多表表关联查询 inner Join left join right join

    Mysql多表表关联查询 inner Join left join right join

  10. SQL Left Join, Right Join, Inner Join, and Natural Join 各种Join小结

    在SQL语言中,存在着各种Join,有Left Join, Right Join, Inner Join, and Natural Join等,对于初学者来说肯定一头雾水,都是神马跟神马啊,它们之间到 ...

随机推荐

  1. [Android] 开源框架 xUtils HttpUtils 代理设置 (Temporary Redirect错误)

    今天简单学习了一下xUtils的使用 https://github.com/wyouflf/xUtils 其中用到HttpUtils模块时,发现总是出现Temporary Redirect 错误. 查 ...

  2. git--简单操作

    Git简介 一.      安装 下载地址: https://git-scm.com/downloads: https://pan.baidu.com/s/1kU5OCOB#list/path=%2F ...

  3. mysql状态分析之show global status

    这里整理下mysql global status的相关命令,在计算监控数据的时候需要用到 一.慢查询 show variables like '%slow%'; +------------------ ...

  4. px、dp、sp、mm、in、pt这些单位有什么区别?

    相信每个Android新手都会遇到这个问题,希望这篇帖子能让你不再纠结. px: 即像素,1px代表屏幕上一个物理的像素点: px单位不被建议使用,因为同样100px的图片,在不同手机上显示的实际大小 ...

  5. python基础-第十二篇-12.1jQuery基础与实例

    一.查找元素 1.选择器 基本选择器 $("*") $("#id") $(".class") $("element") ...

  6. 网络爬虫之scrapy框架详解

    twisted介绍 Twisted是用Python实现的基于事件驱动的网络引擎框架,scrapy正是依赖于twisted, 它是基于事件循环的异步非阻塞网络框架,可以实现爬虫的并发. twisted是 ...

  7. Linux上安装rz和sz命令

    简介 lrzsz 官网入口:http://freecode.com/projects/lrzsz/ lrzsz是一个unix通信套件提供的X,Y,和ZModem文件传输协议 windows 需要向ce ...

  8. getApplicationContext()、Activity.this、 getBaseContext区别

    getApplicationContext()返回应用的上下文,生命周期是整个应用,应用退出它才被摧毁 Activity.this 返回当前activity的上下文,属于activity ,activ ...

  9. Oracle中查看建立索引和使用索引的注意点

    一.查看和建立索引 select * from user_indexes where table_name = 'student' create index i_student_num on stud ...

  10. Android Studio下编译调试 ndk 的示例

    https://github.com/googlesamples/android-ndk https://github.com/googlesamples android studio 手动安装cma ...