linq 左连接右连接总结

背景:一位同事问到了linq为什么要像网上这样写......其实我也懵逼了,因为一直都是直接使用linq的语法,至于为什么会是这样的语法这种问题就好比如问:你问什么吃饭....我没办法给你从人体的构造说起..我只能回答我饿了....至于为什么饿再深究的问题这需要科学家给你答案...,后面想了想这样问的原因可能是跟我一样对这两个连接不够深入的,那就深入详细的做个比较。 

回到主题首先:

基础数据,构造两个有初始数据的list;

            Employees defaultPet = new Employees { id = 0,depid = 0, name = "default"};

            //a表
            List<Employees> emp = new List<Employees>()
            {
                new Employees {id = 1, depid = 1, name = "小李"},
                new Employees {id = 2, depid = 2, name = "小张"},
new Employees {id = 3, depid = 3, name = "小陈"}, };
//b表 List<Department> dept = new List<Department>() { new Department {id = 1, title = "财务"}, new Department {id = 2, title = "人事"} };

 

 然后如此写道:

left join and right join

            //left join
            var model2 = from a in emp
                join b in dept on a.depid equals b.id
                select new
                {
                    a.name,
                    b.title,
                };

            //right join
            var model3 = from b in dept
                         join a in emp on b.id equals a.depid 
                         select new
                         {
                             b.title,
                             a.name,
                         };

result:

左右的结果是一致的,但是不是是想要的结果,少了小陈,虽然b表没有小陈的归属部门,但是这是左连..

从语法上看,sql 会有这样的 写法

1.  select   a.*,b.*   from   a   left   join   b     on   a.id=b.parent_id   

2.select   a.*,b.*   from   a   right   join   b     on   a.id=b.parent_id 

然后看其他找的方法,加了DefaultIfEmpty() (MSDN:https://msdn.microsoft.com/zh-cn/library/system.linq.enumerable.defaultifempty.aspx)

然后我也参考改了一下:

           var model = from a in emp
                join b in dept on a.depid equals b.id into joinEmpDept
                        from b in joinEmpDept.DefaultIfEmpty()
                select new
                {
                    a.name,
                    b.title,
                };

 

对DefaultIfEmpty用到linq里面做了查询得出的结论: DefaultIfEmpty是在左右连接为空对象时就返回一个空的序列。(我理解的比较肤浅)

然后验证了一下。

            var model = from a in emp
                join b in dept on a.depid equals b.id into joinEmpDept
                        from b in joinEmpDept
                select new
                {
                    a.name,
                    b.title,
                };

result

返回结果里面有了小陈..

我把B表的初始化数据做了注释:

            //b表
            List<Department> dept = new List<Department>()
            {
                //new Department {id = 1, title = "财务"},
                //new Department {id = 2, title = "人事"}
            };

resule

结果是返回的是空集合,运行正常。

然后我把DefaultIfEmpty加上,没错抛锚了....空异常..

result:

“System.NullReferenceException”类型的未经处理的异常在 ConsoleApplication1.exe 中发生 

得出的结果是如果将集合 into 到标识中取的时候如果关联的表无数据的时候键值为空,当返回的字段 new{a.name,b.title}做筛选的时候title的值是空的null,对null取值理所当然的会报错。

正确的写法是对title做个判断,如下

            var model = from a in emp
                join b in dept on a.depid equals b.id into joinEmpDept
                        from b in joinEmpDept.DefaultIfEmpty()
                select new
                {
                    a.name,
                    //b.title,
                    title=b==null?"":b.title,
                };

result

输出正常,只是输出的只有title没有就是空字符串而已;

 

总结:1.DefaultIfEmpty的作用(返回 IEnumerable<T> 的元素;如果序列为空,则返回一个具有默认值的单一实例集合。)通俗点就是把本例子的小陈(小陈在b表并无数据可关联)那条数据返回,不管有没关联上。

        2.如果你的左右关联用的是 ..into tmp from a tmp.DefaultIfEmpty()方式输出,记得把null判断加上,否则会抛异常。

        

 

posted on 2016-04-05 14:39  晴朗_Raymond  阅读(349)  评论(0编辑  收藏  举报