我們先來一段最基本的 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. Django学习笔记第一篇--Hello,Django

    一.Django的安装: 1.python虚拟运行的环境的安装以及安装django: sudo pip install virtualenv export VIRTUALENV_DISTRINUTR= ...

  2. [移动云计算开发 01] 解决 windows 7 安装设置 nginx 出现端口占用的问题

    一开始 到nginx官网 http://nginx.org/en/download.html 下载 1.4.2版本,解压安装到自己希望设置的文件夹即可, 但是打开localhost却出现了 “NOT ...

  3. open live writer 代码着色插件

    插件地址1: http://files.cnblogs.com/files/zsy/OpenLiveWriter.CNBlogs.SourceCode.zip 下载,解压,把里面的文件放到最新的 ap ...

  4. win7卸载IE11

    好多人升级了IE11后发现各种不好用,比如经常卡死,无响应.调试工具不好用等缺点. 现在告诉你如何卸载IE11 查看已安装的更新 右键wie卸载,即可需要重启

  5. 如何自定义JSTL标签与SpringMVC 标签的属性中套JSTL标签报错的解决方法

    如何自定义JSTL标签 1.创建一个类,从SimpleTagSupport继承 A) 通过继承可以获得当前JSP页面上的对象,如JspContext I) 实际上可以强转为PageContext II ...

  6. Strut2流程分析-----从请求到Action方法()

    手写请求会通过strutsPrepareAndExcuteFliter的doFilter()方法 然后会调用StrutsActionProxy类的excute()方法,生成一个代理类(ActionPr ...

  7. 2017-2018-2 20165330 实验四《Android程序设计》实验报告

    下载与安装Android Studio 下载地址:Download Android Studio 安装教程参考Android开发简易教程 实验内容 码云链接 任务一 参考<Java和Androi ...

  8. 2017 Multi-University Training Contest - Team 2——HDU6050 Funny Function

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6050 题意:题目很短自己看吧, 就是这个递推式子,说的很清楚了,让你求F(m,1).题解里面分什么奇偶 ...

  9. Java/android 里ClassName.this和this的使用

    如果在内部类里面用this就是指这个内部类的实例,而如果用OuterClassName.this就是它外面的那个类的实例 ClassName.this这个用法多用于在nested class(内部类) ...

  10. wcur LOCATE +

    w字符串处理 DROP PROCEDURE IF EXISTS w_unique; DELIMITER /w/ CREATE PROCEDURE w_unique() BEGIN DECLARE do ...