LINQ TO SQL 中的join

      join对于喜欢写SQL的朋友来说还是比较实用,也比较容易接受的东西。在LINQ TO SQL中,写多表查询,同样可以写join,只是它有它自己的语法要求而已,语义都是一样的,下面我来讲下LINQ TO SQL中的join最基本的形式:都是最简单的,当然还有其它方面的内容,如:怎样加上过滤条件,如何分组,如何排序等等,为了单纯说join的用法,这里就简化下。

from c in Customers
join p 
in Purchases on c.ID equals p.CustomerID
select c.Name 
+ " bought a " + p.Description


      生成的SQL:

SELECT ([t0].[Name] + @p0) + [t1].[Description] AS [value]
FROM [Customer] AS [t0]
INNER JOIN [Purchase] AS [t1] ON ([t0].[ID]) 
= [t1].[CustomerID]

 

     通过生成的SQL,我们可以非常清晰的看出,显示的使用了inner join,它的基本要求好下:
         1:包含join和on关键字,如果只有join没有on,会报语法错误。

         2:外键关联时,用的是关键字equals,而不能像SQL一样用等号。

         3:必须显示调用要显示的字段。即要出现select 字段,否则会报错。

      LINQ TO SQL与传统SQL的相同点:

        1:join的用法,并不关心主表在前还是在后,最终的结果都是相同的。上面的查询我们也可以这样写。

from p in Purchases
    join c 
in Customers on p.CustomerID equals c.ID
    select c.Name 
+ " bought a " + p.Description;

        2:LINQ TO SQL同样支持两表以上的关联,

from c in Customers
join p 
in Purchases on c.ID equals p.CustomerID           // first join
join pi in PurchaseItems on p.ID equals pi.PurchaseID     // second join
select new
{
    c.Name, p.Description, pi.Detail
}

 

     LINQ TO SQL与传统SQL的不同点:

       1:LINQ TO SQL中的join,如果带有into,可以提前对表进行过滤条件的操作,而不用等到两表进行迪卡尔积产生虚似表后再进行join on的条件过滤。

Code

       产生的SQL:

Code

  

      2:LINQ TO SQL包含一个groupjoin的概念,来看下MSDN对它的定义:

           Queryable..::.GroupJoin 方法:基于键相等对两个序列的元素进行关联并对结果进行分组。这样情况一般都发生在一对多的情况,以主表的主键为分组对象,通过主表的主键来查询出子表的集合。

           拿客人和消费记录表来说吧:一个客人会有多笔消费,我们要想得到所有客人的所有消费情况及客人姓名,即最外层的集合对象是所有客人信息,而客人的消费信息通过一个EntitySet集合来体现。在传统SQL中要想通过一个查询是做不到的,因为传统的SQL返回的只是一个具体的集合,具体记录中是不能再包含子记录的。而LINQ TO SQL则可以做到,可以通过主表记录的EntitySet属性来包含子表的集合。

var list =     (from c in db.Customers
join p in db.Purchases on c.ID equals p.CustomerID
into custPurchases
select new
{custPurchases,c.Name}).ToList ();

 

             效果图:如图一,

           可以非常清楚的看出子表Puchase的内容以集合Puchase出现在最终的结果中,另外一列的内容是客户名。我们可以非常方便的取用户的某些信息。

//第一个用户的所有消费记录
            List<Purchase> _list = list[0].custPurchases .ToList<Purchase >() ;
            
//取第一个用户的第一条消费记录的价格
            decimal dPrice = _list[0].Price;


           可以看出LINQ模式对于开发效率还是有很大程度提高的,完全面向对象,逻辑性好,阅读性强。

           对应的SQL:

SELECT [t1].[ID], [t1].[CustomerID], [t1].[Date], [t1].[Description], [t1].[Price], (
    SELECT COUNT(
*)
    FROM [Purchase] AS [t2]
    WHERE ([t0].[ID]) 
= [t2].[CustomerID]
    ) AS [value], [t0].[Name]
FROM [Customer] AS [t0]
LEFT OUTER JOIN [Purchase] AS [t1] ON ([t0].[ID]) 
= [t1].[CustomerID]
ORDER BY [t0].[ID], [t1].[ID]

 

           效果图:如图二,传统SQL看起来是一个完整的集合,它没有子对象的概念。

 

         总结:上面的所有语句都可以用等效的拉姆达表态式来代替,只不过如果是像我一样的初学者,总觉的看拉姆达表达示特别别扭,用类似SQL的语句会容易接受些。join可以和上篇文章讲的selectMany来相互转换。要想join生成LEFT OUT JOIN,同样可以用DefaultIfEmpty()来实现,有兴趣的朋友可以试下。


注:
   文中参考nutshell示例

 

 

 

posted on 2008-12-21 11:19  min.jiang  阅读(33472)  评论(15编辑  收藏  举报