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判断加上,否则会抛异常。