本节讲join操作。我们知道,T-sql中,有三种最基本的join,inner join, left join, 和right join。 而dlinq并不支持right join。道理很简单,right join以right表为基础,left表中没有对应记录的,将以null值填充。而dlinq以left表做为主表创建对象。如果一个对象为null,你如何获取它的其他的属性呢?
在C# 3.0入门系列(四)-之Select操作一文中,我们提到了query expression首先会被翻译成标准的API, 而dlinq在join操作中,一共为我们提供了三个API.它们是Join, SelectMany和GroupJoin
Join
在101 的sample中,并没有join的例子。当一个query expression 有join字句时,而没有into字句,它将会被翻译成join方法。如,以Customers为主表,Orders为子表,用CustomerID 做关联进行join操作。
var q =
from c in db.Customers
join o in db.Orders on c.CustomerID equals o.CustomerID
select new { c.CustomerID, o.EmployeeID };
它将会被翻译成
var q = db.Customers.Join(db.Orders, c => c.CustomerID, o => o.CustomerID, (c, o) => new { c.CustomerID, o.EmployeeID });
join方法的第一个参数,为子表,第二个参数,表示主表中的选择键,第三个参数为子表中的对应键,第四个为最终筛选结果。大家需要注意的时,因为参数的顺序是确定的,所以在写dlinq语句时,c.CustomerID equals o.CustomerID 的顺序是不能变的。
该语句所产生的T-sql语句为
SELECT [t0].[CustomerID], [t1].[EmployeeID]
FROM [Customers] AS [t0]
INNER JOIN [Orders] AS [t1] ON [t0].[CustomerID] = [t1].[CustomerID]
SelectMany
在101sample中,给了4个SelectMany的例子。会被翻译成SelectMany需要满足2个条件。1,query语句中没有join和into,2,必须出现EntitySet。 关于EntitySet,请参考C#3.0进阶系列(一)-从映射讲起
先看第一个例子
var q =
from c in db.Customers
from o in c.Orders
where c.City == "London"
select o;
Customers与Orders是1:M的关系。即Orders在Customers类中,以EntitySet出现。所以第二个from是从c.Orders而不是db.Orders里进行筛选。定义了他们关系的Mapping Code用Attribute保存了他们的关系。如
[Association(Name="Order_OrderDetail", Storage="_OrderDetails", OtherKey="OrderID")]
[Association(Name="Order_OrderDetail", Storage="_Order", ThisKey="OrderID", IsForeignKey=true)]
所以,你就不用担心,dlinq是否知道该按那个键进行关联。有兴趣的朋友,可以自己修改这里的OtherKey和ThisKey的值,看看翻译的T-sql语句是否变了。
第二个例子
var q =
from p in db.Products
where p.Supplier.Country == "USA" && p.UnitsInStock == 0
select p;
这个例子,直接就使用了p.Supplier.Country 做条件,这样,也间接关联了Supplier表。该语句生成的T-sql语句更是值得揣摩,这大概是Left Out Join 的最简单的Dlinq语句。
SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
FROM [dbo].[Products] AS [t0]
LEFT OUTER JOIN [dbo].[Suppliers] AS [t1] ON [t1].[SupplierID] = [t0].[SupplierID]
WHERE ([t1].[Country] = @p0) AND ([t0].[UnitsInStock] = @p1)
-- @p0: Input String (Size = 3; Prec = 0; Scale = 0) [USA]
-- @p1: Input Int32 (Size = 0; Prec = 0; Scale = 0) [0]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 2.0.20612.0