深入剖析linq的联接

内联接

from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
join b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[3]{"李四","数学","100"}
                }
    on a[0] equals b[0]
select new {User=a,Score=b}

结果的结构如下

注意结果里没有a表的“王五”数据

总结:内联接用“join 数据源 on 条件"语法,会将左表(即写在前面的表)的每一条记录和右表(即写在后面的表)的每一条记录进行比较,如果左表有x条记录,右表有y条记录,比较会有x*y次比较,但最后的结果不会有x*y条,而是在x*y条里过滤出符合on条件的记录,有点类似“笛卡尔积+条件判断”的操作。

上面的内联接可完全改成两个from操作(进行笛卡尔积求值),结果的结构是完全一样的

from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
from b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[2]{"李四","100"}
                }
    where a[0]==b[0]
select new {User=a,Score=b}

写到这,可能会问,那所有的内联接操作都改成几个from表就行,还用得着join on的内联接吗?答案是内联接比单纯对几个表进行笛卡尔积求值“效率高很多”,假设有a,b,c三个表,分别为x,y,z条记录,如果用笛卡尔积算法(linq代码如:from a in tab_a from b in tab_b from c in tab_c where ...... select ....),一共会进行x*y*z次连接操作,并对x*y*z条记录进行where过滤;但如果用内联接(linq代码如:from a in tab_a join b in tab_b on ... join c in tab_c on ... select ....),每一次的内联接会基于上一次的结果来进行下一次的操作,即a表和b表进行x*y次操作后,最后可能只得出w条记录(此时的w可能远小于x*y),然后再对c表进行w*z次操作,两者比较x*y*z可能远大于w*z。如果不是a,b,c三个表,而是更多的表进行联接,效率就差距很大了。

组联接

from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
join b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[3]{"李四","数学","100"}
                }
    on a[0] equals b[0] into b_group
select new {User=a,Score=b_group}

结果结构

总结:内联接用“join 数据源 on 条件 into 新数据源"语法,会以左表(即写在前面的表)的每一条记录为一组,分别和右表(即写在后面的表)的每一条记录进行比较,如果左表有x条记录,右表有条记录,比较会有x*y次比较,但结果只有x组,而每一组可能有<=y条>=0条记录。

如果要对上面的代码进行输出操作,会有两次循环操作

var query=from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
join b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[3]{"李四","数学","100"}
                }
    on a[0] equals b[0] into b_group
select new {User=a,Score=b_group};

foreach(var p1 in query){
    Console.WriteLine($@"{p1.User[0]}的成绩如下:");
    foreach(var p2 in p1.Score){
        Console.Write($@"---{p2[1]}-{p2[2]}---");
    }
    Console.WriteLine();
}

结果输出如下:

张三的成绩如下:
---英语-90------语文-70---
李四的成绩如下:
---数学-100---
王五的成绩如下:

可以发现,单是用组联接其实返回的结果在有此情况下是不方便进行处理的,因为要对每一个组再进行循环才能取到我们最终想要的值,下面介绍用“内联接+组联接”来方便的得到我们想要的值

内联接+组联接

代码如下

from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
join b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[3]{"李四","数学","100"}
                }
    on a[0] equals b[0] into b_group
from b2 in b_group
select new {User=a,Score=b2}

结果的结构如下:

如果细心的朋友会注意到现在的结果和最前面“内联接”一节的结果是一样的。

对代码稍作修改

from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
join b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[3]{"李四","数学","100"}
                }
    on a[0] equals b[0] into b_group
from b2 in b_group
select new {User=a,Score=b_group}

只是将

select new {User=a,Score=b2}改成了
select new {User=a,Score=b_group}

结果的结构变成如下

左外联接

代码如下

from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
join b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[2]{"李四","100"}
                }
    on a[0] equals b[0] into temp
from b in temp.DefaultIfEmpty()
select new{User=a, Score=b}

结果如下

代码稍作修改

from a in new List<string[]>{
                            new string[2]{"张三","男"},
                            new string[2]{"李四","女"},
                            new string[2]{"王五","男"}
                            }
join b in new List<string[]>{
                new string[3]{"张三","英语","90"},
                new string[3]{"张三","语文","70"},
                new string[2]{"李四","100"}
                }
    on a[0] equals b[0] into temp
from b in temp.DefaultIfEmpty()
select new{User=a, Score=temp}

结果的结构变成

原文地址:https://www.cnblogs.com/shengyu-kmust/p/8424427.html

时间: 2024-09-30 19:08:54

深入剖析linq的联接的相关文章

linq左联接

from t in _entity.TB_OrderInfo                                 where t.OrderCode == courOrderCode || t.CounierCode == courOrderCode && t.IsDel == "N"                                 join b in _entity.TB_CustomerInfo on t.CustomerCode equ

C# LinQ 左联接加分组聚合查询

真是醉了,前段时间摸索半天今天一写又忘了,特此写下来备忘,望大婶指点 from a in Table1 join b in Table2 on a.Id equals b.Id2 into e from f in e.DefaultIfEmpty() group new { a.Id1, a.Name, f.id2 } by new { a.Id,//一表的ID a.Name,//一表的字段(Name) f.id2//二表的字段(type) } into c select new Sontype

LINQ系列:联接操作符

联接是指将一个数据源对象与另一个数据源对象进行关联或联合的操作.这两个数据源对象通过一个共同的值或属性进行关联. LINQ的联接操作符将包含可匹配(或相同)关键字的两个或多个数据源中的值进行匹配. LINQ有两个联接操作符:join和groupjoin. 1. join join操作符类似于T-SQL中的inner join,将一个数据源与另一个数据源相联接,根据两个数据源中相等的值进行匹配. 1>. 原型定义 public static IEnumerable<TResult> Joi

Linq联接

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Linq联接 { class Program { public class Student { public int stID; public string LastName; } public class CourseStudent { public string CourseName; public i

NHibernate3剖析:Query篇之NHibernate.Linq自定义扩展

系列引入 NHibernate3.0剖析系列分别从Configuration篇.Mapping篇.Query篇.Session策略篇.应用篇等方面全面揭示NHibernate3.0新特性和应用及其各种应用程序的集成,基于NHibernte3.0版本.如果你还不熟悉NHibernate,可以快速阅读NHibernate之旅系列文章导航系列入门,如果你已经在用NHibernate了,那么请跟上NHibernate3.0剖析系列吧. NHibernate专题:http://kb.cnblogs.com

NHibernate3剖析:Query篇之NHibernate.Linq增强查询

系列引入 NHibernate3.0剖析系列分别从Configuration篇.Mapping篇.Query篇.Session策略篇.应用篇等方面全面揭示NHibernate3.0新特性和应用及其各种应用程序的集成,基于NHibernte3.0版本.如果你还不熟悉NHibernate,可以快速阅读NHibernate之旅系列文章导航系列入门,如果你已经在用NHibernate了,那么请跟上NHibernate3.0剖析系列吧. NHibernate专题:http://kb.cnblogs.com

linq to entity 左联接 右连接 以及内连接写法的区别(转)

linq to entity 左连接 右连接 以及内连接写法的区别  还有就是用lambda表达式怎么写,那个效法效率高些? [解决办法]左连右连还是内连这个其实你不需要关心.只需要根据实体的映射关系写查询,框架会自动帮你生成的.至于linq查询语法与扩展方法的效率,应该是一样的,比如: C# code var users=(from u in db.Users where u.UserRoleId==1 select u) .ToList(); var users2=db.Users.Wher

.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)

阅读目录: 1.环路执行对象模型.碎片化执行模型(假递归式调用) 2.N层对象执行模型(纵横向对比链式扩展方法) 3.LINQ查询表达式和链式查询方法其实都是空壳子 4.详细的对象结构图(对象的执行原理) 5.IQueryable<T>与IQueryProvider一对一的关系能否改成一对多的关系 6.完整的自定义查询 1]. 环路执行对象模型.碎片化执行模型(假递归式调用) 这个主题扯的可能有点远,但是它关系着整个LINQ框架的设计结构,至少在我还没有搞懂LINQ的本意之前,在我脑海里一直频

C# LINQ 详解 From Where Select Group Into OrderBy Let Join

目录 1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. 概述 LINQ的全称是Language Integrated Query,中文译成"语言集成查询".LINQ作为一种查询技术,首先要解决数据源的封装,大致使用了三大组件来实现这个封装,分别是LINQ to Object.LINQ to ADO.NET.LINQ to XML.它们和.NET