我們在做SQL查詢的時候經常會用到Inner Join,Left Join,笛卡爾積等等,連接方式的概念方面我想也不用給予太多解釋,
我們今天的重點是讓大家熟悉LINQ是如何使用Join來實現常用的表連接的。
創建測試用類:
- class Customer
- {
- public int CustomerId { get; set; }
- public string Name { get; set; }
- public int Age { get; set; }
- }
- class Product
- {
- public int ProductId { get; set; }
- public string Name { get; set; }
- public string Origin { get; set; }
- }
- class Order
- {
- public int OrderId { get; set; }
- public int CustomerId { get; set; }
- public List<Product> Products { get; set; }
- }
我們用以下例子來熟悉 Join 關鍵字的用法。
1.Inner Join:
- CreateEntities();
- var query = from c in customers
- join o in orders on c.CustomerId equals o.CustomerId
- where o.OrderId == 2
- select c;
- foreach (var customer in query)
- {
- Console.WriteLine("Id:{0}, Name:{1}", customer.CustomerId, customer.Name);
- }
運行結果:
Id:1, Name:CA
上面這個是常見的內連接的例子,和SQL語法也很相似,但有以下幾點要注意:
(1).連接條件: c.CustomerId equals o.CustomerId 只能使用 equals 不能用 =,==,等於 等表示。
以為LINQ的設計者認為 幾乎所有的連接條件都是 = 條件不會出現 >,<,!= 等情況因此使用了個關鍵字來描述表連接條件。
(2).條件順序:c.CustomerId equals o.CustomerId ,range variable: c 和b之前的順序不能顛倒。
2.Group Join:
也許大家對Group Join的概念不太了解,沒關系讓我們通過例子來認識它:
- CreateEntities();
- var query = from c in customers
- join o in orders on c.CustomerId equals o.CustomerId into os
- select new { c, os };
- foreach (var item in query)
- {
- Console.WriteLine("Customer Id:{0}, Name:{1}", item.c.CustomerId, item.c.Name);
- foreach (var o in item.os)
- {
- Console.WriteLine("--Order Id:{0}", o.OrderId);
- }
- }
結果:
Customer Id:1, Name:CA
--Order Id:1
--Order Id:2
Customer Id:2, Name:CB
--Order Id:4
Customer Id:3, Name:CC
--Order Id:3
Customer Id:4, Name:CD
Press any key to continue . . .
以上查詢返回的結果:和Group By 返回的結果非常的相似:一個KEY對象對應一個集合。
要實現Group Join我們要引入一個關鍵字:into
但使用時要注意一下幾點:
(1).使用into 關鍵字后 join 后面的 range variable:o 在后面的表達式塊中就失去了作用域。
(2).range variable:os 通常情況下都是IEnumerable<T>類型的。
3.Left Join:
Left Join 我們在SQL里經常用到,讓我們來看看LINQ里怎么實現它:
- CreateEntities();
- var query = from c in customers
- join o in orders on c.CustomerId equals o.CustomerId into os
- from o2 in os.DefaultIfEmpty(
- new Order { OrderId = 0, CustomerId = 0, Products = new List<Product>() })
- select new { c, o2 };
- foreach (var item in query)
- {
- Console.WriteLine("Customer Id:{0}, Name:{1}--Order Id:{0}",
- item.c.CustomerId, item.o2.OrderId);
- }
結果:
Customer Id:1, Name:1--Order Id:1
Customer Id:1, Name:2--Order Id:1
Customer Id:2, Name:4--Order Id:2
Customer Id:3, Name:3--Order Id:3
Customer Id:4, Name:0--Order Id:4
Press any key to continue . . .
我們可以看到Left Outer Join 的語法進一步的復雜化了,結果也有細微的不同。
(1).從語法上:
from o2 in os.DefaultIfEmpty(
new Order { OrderId = 0, CustomerId = 0, Products = new List<Product>() })
主要區別在於以上者1句語句。查詢方法DefaultIfEmpty 用於定義當查詢記錄為空時,預定義默認值。再從其集合中取出子元素。
(2).從結果上: 我們在遍歷查詢結果時可以發現Left Join相似於Inner Join結果都是“平面”的,然而Group Join返回的結果具有層次性。
題外:
由於C#是面向對象的,往往會通過對象與對象間的外系來實現數據間關系。有時表達2個之間的關系也可以不使用Join關鍵字,
因此Join關鍵字其實在實際LINQ查詢表達式中用的不是很多。