从上篇文章到现在,已经有好几个星期没有更新了。希望在这段时间里面你们也有用自己的时间来探索如何构建自己的提供程序。我也一直在关注别人的各种各样的“LINQ to XXX”的项目,感觉都很不错。今天我将向你们介绍如何在我的提供程序中添加连接查询的功能,比起只支持select和where来,支持join将能提供更多有趣的用法。
var query = from c in db.Customers from o in db.Orders where c.CustomerID == o.CustomerID selectnew { c.ContactName, o.OrderDate };
当然,也可以使用显式的join子句。
1 2 3
var query = from c in db.Customers join o in db.Orders on c.CustomerID equals o.CustomerID selectnew { c.ContactName, o.OrderDate };
这两个查询会得到相同的结果,那么为什么做同一件事会有两种不同的方式呢?
原因有点复杂,但我会尝试解释清楚。显式连接要求我们指定两个匹配的键表达式,用数据库的术语来说,就是等值连接。而嵌套from子句具有更大的灵活性。显式连接具有如此限制的原因是,通过这种限制,使得LINQ to Objects的实现不必去分析和重写查询,进而使执行更加高效。好消息是,在数据库中用到的连接几乎都是等值连接。
var query = from c in db.Customers where c.CustomerID == "ALFKI" join o in db.Orders on c.CustomerID equals o.CustomerID selectnew { c.ContactName, o.OrderDate };
Console.WriteLine(query);
foreach (var item in query) { Console.WriteLine(item); }
SELECT t2.ContactName, t4.OrderDate FROM ( SELECT t1.CustomerID, t1.ContactName, t1.Phone, t1.City, t1.Country FROM ( SELECT t0.CustomerID, t0.ContactName, t0.Phone, t0.City, t0.Country FROM Customers AS t0 ) AS t1 WHERE (t1.CustomerID = 'ALFKI') ) AS t2 INNER JOIN ( SELECT t3.OrderID, t3.CustomerID, t3.OrderDate FROM Orders AS t3 ) AS t4 ON (t2.CustomerID = t4.CustomerID) { ContactName = Maria Anders, OrderDate = 8/25/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 10/3/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 10/13/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 1/15/1998 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 3/16/1998 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 4/9/1998 12:00:00 AM }
大部分的LINQ to SQL引擎都会尽可能地将CROSS APPLY转换成CROSS JOIN。如果不这样做的话,LINQ to SQL在SQL2000里面可能就不能正常执行。当然,即使这样,还是有一些查询是无法转换成CROSS JOIN的。为了在这个示例提供程序里面添加这个特性,我还要做许多工作。虽然并不是很情愿,但是我也没有那么绝情,所以还是做了一点,算是抛砖引玉吧。我会处理一些简单的情况,将其转换成CROSS JOIN。
var query = from c in db.Customers where c.CustomerID == "ALFKI" from o in db.Orders where c.CustomerID == o.CustomerID selectnew { c.ContactName, o.OrderDate };
Console.WriteLine(query);
foreach (var item in query) { Console.WriteLine(item); }
SELECT t6.ContactName, t6.OrderDate FROM ( SELECT t5.CustomerID, t5.ContactName, t5.Phone, t5.City, t5.Country, t5.OrderID, t5.CustomerID1, t5.OrderDate FROM ( SELECT t2.CustomerID, t2.ContactName, t2.Phone, t2.City, t2.Country, t4.OrderID, t4.CustomerID AS CustomerID1, t4.OrderDate FROM ( SELECT t1.CustomerID, t1.ContactName, t1.Phone, t1.City, t1.Country FROM ( SELECT t0.CustomerID, t0.ContactName, t0.Phone, t0.City, t0.Country FROM Customers AS t0 ) AS t1 WHERE (t1.CustomerID = 'ALFKI') ) AS t2 CROSS JOIN ( SELECT t3.OrderID, t3.CustomerID, t3.OrderDate FROM Orders AS t3 ) AS t4 ) AS t5 WHERE (t5.CustomerID = t5.CustomerID1) ) AS t6
{ ContactName = Maria Anders, OrderDate = 8/25/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 10/3/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 10/13/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 1/15/1998 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 3/16/1998 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 4/9/1998 12:00:00 AM }
SELECT t2.ContactName, t5.OrderDate FROM ( SELECT t1.CustomerID, t1.ContactName, t1.Phone, t1.City, t1.Country FROM ( SELECT t0.CustomerID, t0.ContactName, t0.Phone, t0.City, t0.Country FROM Customers AS t0 ) AS t1 WHERE (t1.CustomerID = 'ALFKI') ) AS t2 CROSS APPLY ( SELECT t4.OrderID, t4.CustomerID, t4.OrderDate FROM ( SELECT t3.OrderID, t3.CustomerID, t3.OrderDate FROM Orders AS t3 ) AS t4 WHERE (t2.CustomerID = t4.CustomerID) ) AS t5
{ ContactName = Maria Anders, OrderDate = 8/25/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 10/3/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 10/13/1997 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 1/15/1998 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 3/16/1998 12:00:00 AM } { ContactName = Maria Anders, OrderDate = 4/9/1998 12:00:00 AM }