1 摘要
文章通过一个简单的实例对Linq中的Join操作进行演示,并在文章的最后对Join操作相关知识点进行简单的总结。
2 实例演示
1) 新建数据库MyTestDB,在数据库中新建数据表tb_Class和tb_Student,两表的定义如下图所示。
图1 tb_Class的定义 图2 tb_Student的定义
2) 向数据表tb_Class和tb_Student插入下图所示测试数据。
图3 tb_Class的测试数据
图4 tb_Student的测试数据
3) 新建控制台应用程序LinqJoinExp。
4) 本例中使用ADO.NET Entity Framework来访问数据库的数据,使用ADO.NET Entity Framework访问数据库前需要新建ADO.NET实体数据模型,本例中新建的ADO.NET实体数据模型名称为MyTestDB,具体操作可以参考文章《Ado.Net Entities Framework实例》。
5) 下面使用Join分别实现tb_Class左连接tb_Student,tb_Class右连接tb_Student,tb_Class内连接tb_Student操作。详细代码如下所示。
//************************************************************ // // LINQ JOIN类示例代码 // // Author:三五月儿 // // Date:2014/08/02 // // http://blog.csdn.net/yl2isoft // //************************************************************ using System; using System.Linq; namespace LinqJoinExp { class Program { static void Main(string[] args) { DoLeftJoin();//左连接 PrintStar(); DoRightJoin();//右连接 PrintStar(); DoJoin();//连接 } /// <summary> /// 左连接 /// </summary> public static void DoLeftJoin() { using (MyTestDBEntities myTestDBEntities = new MyTestDBEntities()) { var leftJoinResult = from c in myTestDBEntities.tb_Class join s in myTestDBEntities.tb_Student on c.classid equals s.classid into joinedResult from jr in joinedResult.DefaultIfEmpty() select new { ClassId = c.classid, ClassName = c.classname, Teacher = c.teacher != null ? c.teacher : string.Empty, StudentId = jr.id != null ? jr.id : 0, StudentName = jr.name != null ? jr.name : string.Empty, StudentAge = jr.age != null ? jr.age : 0, StudentScore = jr.score != null ? jr.score : 0, }; foreach (var result in leftJoinResult) { Console.WriteLine("ClassId=" + result.ClassId + ","+ "ClassName=" + result.ClassName + ","+ "Teacher=" + result.Teacher + ","+ "StudentId=" + result.StudentId + ","+ "StudentName=" + result.StudentName + ","+ "StudentAge=" + result.StudentAge + ","+ "StudentScore=" + result.StudentScore); } } } /// <summary> /// 右连接 /// </summary> public static void DoRightJoin() { using (MyTestDBEntities myTestDBEntities = new MyTestDBEntities()) { var rightJoinResult = from s in myTestDBEntities.tb_Student join c in myTestDBEntities.tb_Class on s.classid equals c.classid into joinedResult from jr in joinedResult.DefaultIfEmpty() select new { StudentId = s.id, StudentName = s.name, StudentAge = s.age, StudentScore = s.score != null ? s.score : 0, ClassId = jr.classid != null ? jr.classid : 0, ClassName = jr.classname != null ? jr.classname : string.Empty, Teacher = jr.teacher != null ? jr.teacher : string.Empty, }; foreach (var result in rightJoinResult) { Console.WriteLine("ClassId=" + result.ClassId + "," + "ClassName=" + result.ClassName + "," + "Teacher=" + result.Teacher + "," + "StudentId=" + result.StudentId + "," + "StudentName=" + result.StudentName + "," + "StudentAge=" + result.StudentAge + "," + "StudentScore=" + result.StudentScore); } } } /// <summary> /// 连接 /// </summary> public static void DoJoin() { using (MyTestDBEntities myTestDBEntities = new MyTestDBEntities()) { var joinResult = from c in myTestDBEntities.tb_Class join s in myTestDBEntities.tb_Student on c.classid equals s.classid select new { ClassId = c.classid, ClassName = c.classname, Teacher = c.teacher != null ? c.teacher : string.Empty, StudentId = s.id, StudentName = s.name, StudentAge = s.age, StudentScore = s.score != null ? s.score : 0, }; foreach (var result in joinResult) { Console.WriteLine("ClassId=" + result.ClassId + "," + "ClassName=" + result.ClassName + "," + "Teacher=" + result.Teacher + "," + "StudentId=" + result.StudentId + "," + "StudentName=" + result.StudentName + "," + "StudentAge=" + result.StudentAge + "," + "StudentScore=" + result.StudentScore); } } } /// <summary> /// 显示型号分隔符 /// </summary> public static void PrintStar() { Console.WriteLine("**************************************************************************"); } } }6) 运行示例程序,得到下图所示结果。
图5 程序运行结果
7) 在阅读程序的运行结果前,我们先来对程序的结果进行一番预测。
首先,对连接的定义(借鉴SQL中的定义,可以参考文章《JOIN操作实例》)做简单的复习。
根据连接的定义,我们可以得到tb_Class左连接tb_Student,tb_Class右连接tb_Student,tb_Class内连接tb_Student的结果。
表1 tb_Class左连接tb_Student的结果
classid |
classname |
teacher |
id |
name |
age |
classid |
score |
1 |
1班 |
yul |
1 |
zhangs |
12 |
1 |
NULL |
1 |
1班 |
yul |
4 |
liulu |
12 |
1 |
NULL |
2 |
2班 |
wsp |
2 |
lisi |
10 |
2 |
85 |
3 |
3班 |
NULL |
3 |
wangwu |
11 |
3 |
90 |
14 |
4班 |
lisi |
NULL |
NULL |
NULL |
NULL |
NULL |
表2 tb_Class右连接tb_Student的结果
classid |
classname |
teacher |
id |
name |
age |
classid |
score |
1 |
1班 |
yul |
1 |
zhangs |
12 |
1 |
NULL |
2 |
2班 |
wsp |
2 |
lisi |
10 |
2 |
85 |
3 |
3班 |
NULL |
3 |
wangwu |
11 |
3 |
90 |
1 |
1班 |
yul |
4 |
liulu |
12 |
1 |
NULL |
NULL |
NULL |
NULL |
5 |
liujia |
12 |
5 |
88 |
表3 tb_Class内连接tb_Student的结果
classid |
classname |
teacher |
id |
name |
age |
classid |
score |
1 |
1班 |
yul |
1 |
zhangs |
12 |
1 |
NULL |
1 |
1班 |
yul |
4 |
liulu |
12 |
1 |
NULL |
2 |
2班 |
wsp |
2 |
lisi |
10 |
2 |
85 |
3 |
3班 |
NULL |
3 |
wangwu |
11 |
3 |
90 |
将我们根据定义计算得到的结果与程序的运行结果进行对比,两者完全一致。说明,本文的示例程序是正确的,所以,大家完全可以放心的参考本文的示例代码进行学习(文章最后会给出程序源码的下载地址)。这里,有一点需要补充说明一下,根据定义计算得到的结果中,存在大量的NULL值,但是示例程序结果中并不存在NULL值,这是因为示例程序对可能出现NULL值的字段都进行了处理,当某字段值为NULL时,就用0或者空串替换该字段的值,例如:Teacher = c.teacher != null ? c.teacher : string.Empty。
3 知识总结
1) 在Linq中,使用Join就可以完成左连接,右连接,内连接的操作。只是,在进行左右连接操作时,还需要借助于Enumerable.DefaultIfEmpty()方法,此方法位于命名空间System.Linq中,是一个扩展方法,该方法的作用是:返回指定序列的元素,如果序列为空时则使用序列元素对应类型的默认值代替,引用和可空类型的默认值为 null。
2) 通过本文所给示例,可以了解到,linq中左连接与右联接的代码实现没有任何区别,因为“tb_Class右连接tb_Student”本质上与“tb_Student左连接tb_Class”完全相同,所以在实现“tb_Class右连接tb_Student”时,本质上仍然使用的是左连接来实现的,因此,linq中的左右联接本质上都是左连接。
3) 最后,再次强调一下连接的定义,毕竟,只有充分理解了定义的基础上才能进行灵活地应用嘛,呵呵。
原文:http://blog.csdn.net/yl2isoft/article/details/38351447