关于Linq翻译Inner join ,Left join (本文为转载)
我們先來一段最基本的 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 (本文为转载)的更多相关文章
- Linq中join & group join & left join 的用法
Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报 分类: C#(14) 文章 ...
- Linq 多表连接查询join
在查询语言中,通常需要使用联接操作.在 LINQ 中,可以通过 join 子句实现联接操作.join 子句可以将来自不同源序列,并且在对象模型中没有直接关系(数据库表之间没有关系)的元素相关联,唯一的 ...
- LINQ TO SQL 中的join(转帖)
http://www.cnblogs.com/ASPNET2008/archive/2008/12/21/1358152.html join对于喜欢写SQL的朋友来说还是比较实用,也比较容易接受的东西 ...
- MySQL Left Join,Right Join
魂屁,东西发这里了关于Left Join,Right Join的 在讲MySQL的Join语法前还是先回顾一下联结的语法,呵呵,其实连我自己都忘得差不多了,那就大家一起温习吧(如果内容有错误或有疑问, ...
- 浅谈SQL Server中的三种物理连接操作(HASH JOIN MERGE JOIN NESTED LOOP)
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- 左连接,右连接,内连接(left join ,right join,inner join)
浅谈左连接,右连接,内连接(left join ,right join,inner join) 这个问题一直困扰着我,每次遇到就打擦边球,不正面应对.今天索性把这几个连接搞懂了,写下这篇博客, 让跟我 ...
- SQL语句中LEFT JOIN、JOIN、INNER JOIN、RIGHT JOIN的区别?
w3school的一套sql教程: http://www.w3school.com.cn/sql/index.asp left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录.r ...
- join中级篇---------hash join & merge join & nested loop Join
嵌套循环连接(Nested Loop Join) 循环嵌套连接是最基本的连接,正如其名所示那样,需要进行循环嵌套,嵌套循环是三种方式中唯一支持不等式连接的方式,这种连接方式的过程可以简单的用下图展示: ...
- Mysql多表表关联查询 inner Join left join right join
Mysql多表表关联查询 inner Join left join right join
- SQL Left Join, Right Join, Inner Join, and Natural Join 各种Join小结
在SQL语言中,存在着各种Join,有Left Join, Right Join, Inner Join, and Natural Join等,对于初学者来说肯定一头雾水,都是神马跟神马啊,它们之间到 ...
随机推荐
- XE10 塔建 Android 开发环境 (已测试通过)
XE10 塔建 Android 开发环境 1. E:\DevCSS\Android\adt-bundle-windows-x86-20131030\adt-bundle-windows-x86-201 ...
- Objective-C代码学习大纲(1)
2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍了Objective-C代码,很多名词为台 ...
- 170403、java 版cookie操作工具类
package com.rick.utils; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; imp ...
- 飘城旅游网pc,流式,响应式布局
相关视频教程http://pan.baidu.com/s/1o77wirK 我的源码链接:http://pan.baidu.com/s/1czTsKI
- Codeforces Round #427 (Div. 2)—A,B,C,D题
A. Key races 题目链接:http://codeforces.com/contest/835/problem/A 题目意思:两个比赛打字,每个人有两个参数v和t,v秒表示他打每个字需要多久时 ...
- Fractal---poj2083(递归和普通方法打印图形)
题目链接:http://poj.org/problem?id=2083 这题不能用G++提交... 见到两次知道有递归的写法,然而并不会,这次发现并不难: #include<stdio.h> ...
- 爬虫之UserAgent
UserAgent简介 UserAgent中文名为用户代理,是Http协议中的一部分,属于头域的组成部分,UserAgent也简称UA.它是一个特殊字符串头,是一种向访问网站提供你所使用的浏览器类型及 ...
- 5.Git版本库创建
1.什么是版本库呢? 什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何 ...
- LayoutInflater的动态增加控件
在实际开发中LayoutInflater这个类是非常有用的,它的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout下xml布局文件. 而findView ...
- JS通过身份证号获取生日、年龄、性别
<script> function IdCard(UUserCard,num){ if(num==1){ //获取出生日期 birth=UUserCard.substring(6, 10) ...