Linq之Join操作

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) 最后,再次强调一下连接的定义,毕竟,只有充分理解了定义的基础上才能进行灵活地应用嘛,呵呵。

  • 左外连接:从左表那里返回所有的行以及右表中符合指定的匹配条件的行。
  • 右外连接:从右表那里返回所有的行以及左表中符合指定的匹配条件的行。
  • 内连接:仅当至少有一个同属于两表的行符合连接条件时,内连接才返回行。

好了,就到这里了,886。

Linq之Join操作,布布扣,bubuko.com

时间: 2024-12-25 10:42:55

Linq之Join操作的相关文章

使用 Linq 对多个对象进行join操作 C#

class A { public int id { get; set; } public string name { get; set; } } class B { public int id { get; set; } public int age { get; set; } } class C { public int id { get; set; } public string address { get; set; } } private void button8_Click(objec

linq group join

本篇介绍Linq的Group和Join操作,继续使用<Linq 学习(3) 语法结构>中介绍的数据源. GroupGroup是进行分组操作,同SQL中的Group By类似.原型如下: public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(     this IEnumerable<TSource> source,     Func<TSourc

Linq特取操作之ElementAt,Single,Last,First源码分析

Linq特取操作之ElementAt,Single,Last,First源码分析 一:linq的特取操作 First/FirstOrDefault, Last/LastOrDefault, ElementAt/ElementAtOrDefault, Single/SingleOrDefault 二:First/FirstOrDefault 介绍 解释: 用于返回序列中的第一个值 异常: 如果当前集合没有值的话,如果你取第一个值,会抛出throw Error.NoElements();异常. pu

MapReduce实现Reduce端Join操作实例

使用案例: 联接两张表 Table EMP:(新建文件EMP,第一行属性名不要) Name Sex Age DepNo zhang male 20 1 li female 25 2 wang female 30 3 zhou male 35 2 Table Dep:(新建文件DEP,第一行属性名不要) DepNo DepName 1 Sales 2 Dev 3 Mgt Inner join: select Name,Sex,Age,DepName from EMP inner join DEP

mapreduce join操作

上次和朋友讨论到mapreduce,join应该发生在map端,理由太想当然到sql里面的执行过程了 wheremap端 join在map之前(笛卡尔积),但实际上网上看了,mapreduce的笛卡尔积发生在reduce端,下面哥们有个实现过程可以参考(http://blog.csdn.net/xyilu/article/details/8996204).有空再看看 实际上实现过程是不是和他写的代码一样. 前阵子把MapReduce实现join操作的算法设想清楚了,但一直没有在代码层面落地.今天

MySql 中Join操作的用法

SQL标准中的Join的类型: 首先,设置表employees和department的数据为: 1.inner join - on操作类型 内连接inner join是基于连接谓词将两张表(如A和B)的列组合在一起的,产生新的结果表. 例子: SELECT * FROM employees a inner join department b ON a.department_id = b.department_id 查询结果为: 注意:inner join 可以简写为join,该查询得出的结果为两

MapReduce中的Reduce join操作

-------file1[ID NAME]-------- 1 zhangsan2 lisi3 wangwu -------file2[ID VALUE]--------1 452 563 89 -------结果[NAME VALUE]------------zhagnsan 45lisi 56wangwu 89 一般数据库的join操作 a join b  on a.id = b.id 后面的条件在reduce中指的是相同的key,在sql中很容易区分出后面条件的字段到底来自那张表 而在Ma

MapReduce中的Map join操作

可以使用setup进行去读,吧数据读取放到一个容器中,在map段去读的时候,可以根据ID就找出数据,然后再转化回来 map端的join 适用场景,小表可以全部读取放到内存中,两个在内存中装不下的大表,不适合Map端的join操作 在一个TaskTracker中可以运行多个map任务.每个map任务是一个java进程,如果每个map从HDFS中读取相同的小表内容,就有些浪费了.使用DistributedCache,小表内容可以加载在TaskTracker的linux磁盘上.每个map运行时只需要从

MapReduce 实现数据join操作

前段时间有一个业务需求,要在外网商品(TOPB2C)信息中加入 联营自营 识别的字段.但存在的一个问题是,商品信息 和 自营联营标示数据是 两份数据:商品信息较大,是存放在hbase中.他们之前唯一的关联是url.所以考虑用url做key将两者做join,将 联营自营标识 信息加入的商品信息中,最终生成我需要的数据: 一,首先展示一下两份数据的demo example 1. 自营联营标识数据(下面开始就叫做unionseller.txt) http://cn.abc.www/product436