Linq To DataSet 之二(查询多个数据表)

Posted on 2011-01-03 15:15  gmtyt  阅读(3324)  评论(0)    收藏  举报

Linq To DataSet 之二(查询多个数据表)

(2010-08-25 07:47:34)
标签:

it

分类: 数据库

5.2.3 查询多个数据表

通常,一个数据集(DataSet)包含多个数据表(DataTable),而且数据表之间具有一定的关联关系,从而表示一个关系型数据库。通过LINQ to DataSet同样可以轻松查询多个数据表中的数据,这通常需要使用多个from子句进行复合查询,同时通过where子句来进行多个表之间的关系判断。

 

本节的例子中,使用示例代码5-3中创建的数据集合,BuildDataSet()方法创建一个名为Students的数据表,包含两个数据表Students和Scores,前者记录学生信息,包括:姓名(Name)、性别(XingBie)、年龄(Age)、成绩号(ScoreID)。后者记录学生成绩,包括:成绩号(ScoreID)、数学成绩(Math)、语文成绩(Chinese)、英语成绩(English)。其中,字段成绩号是两个表关联字段,通过该字段可以查询学生的成绩信息。

 

示例代码5-3

static DataSet BuildDataSet( )

{

    DataSet ds = new DataSet("Students");                         //创建Students数据集

    //创建Students数据表dtStu,并添加到数据集ds中

    //Students数据表包含学生信息

    DataTable dtStu = new DataTable("Students");

    ds.Tables.Add(dtStu);

    //添加学生信息记录的列信息,包括4列数据:

    //姓名:Name,string类型

    //性别:XingBie,string类型

    //年龄:Age,int类型

    //成绩编号:ScoreID,int类型

    dtStu.Columns.AddRange(new DataColumn[]{

        new DataColumn("Name", Type.GetType("System.String")),

        new DataColumn("XingBie", Type.GetType("System.String")),

        new DataColumn("Age", Type.GetType("System.Int32")),

        new DataColumn("ScoreID", Type.GetType("System.Int32")),

    });

    //添加5个学生信息到数据表dtStu中,分别包括姓名、性别、年龄和成绩编号

    dtStu.Rows.Add("张三", "男", 20, 1);

    dtStu.Rows.Add("李四", "男", 19, 2);

    dtStu.Rows.Add("王霞", "女", 21, 3);

    dtStu.Rows.Add("赵敏", "女", 22, 4);

    dtStu.Rows.Add("吴安", "男", 18, 5);

    //创建Scores数据表,并添加到数据集

    //Scores数据表包含学生成绩记录

    DataTable dtScore = new DataTable("Scores");

    ds.Tables.Add(dtScore);

    //添加成绩记录表的列(字段)信息,包含4个字段:

    //成绩编号:ScoreID,int类型,与Students表的ScoreID字段对应

    //数学成绩:Math,int类型

    //语文成绩:Chinese,int类型

    //英语成绩:English,int类型

    dtScore.Columns.AddRange(new DataColumn[]{

        new DataColumn("ScoreID", Type.GetType("System.Int32")),

        new DataColumn("Math", Type.GetType("System.Int32")),

        new DataColumn("Chinese", Type.GetType("System.Int32")),

        new DataColumn("English", Type.GetType("System.Int32")),

    });

    //添加学生成绩记录,分别包括成绩编号、数学成绩、语文成绩、英语成绩

    dtScore.Rows.Add(1, 80, 75, 78);

    dtScore.Rows.Add(3, 88, 80, 60);

    dtScore.Rows.Add(4, 75, 90, 80);

    dtScore.Rows.Add(5, 59, 80, 75);

    return ds;                                                                              //返回数据集

}

 

查询多个数据表的数据通常通过多个from子句进行联合查询,每个from子句对应一个数据表,同时用where子句来表示多个数据表之间的关系,一般单个where子句表示两个表之间的关系。在进行多表数据查询之前,要明确几个问题:

(1)要在哪些数据表中查询数据?from子句该如何编写?

(2)查询结果包含哪些数据表的哪些字段?select子句该如何编写?

(3)各数据表之间的关系如何进行关联?where子句该如何编写?

(4)是否需要其他的操作,比如排序(orderby子句)、分组(group子句)等?

(5)该查询是使用简单的单个查询实现,还是通过多个查询组合实现?

 

如示例代码5-4所示,方法QueryStuScores()中首先通过BuildDataSet()方法获取数据集和要查询的数据表,其中dtStu表示学生信息数据表,dtScore表示学生成绩数据表。查询query1用于查询数据集合中所有学生的成绩,如果学生没有成绩则不作为结果返回。

query1中,第1个from子句从表dtStu中查询学生信息记录,并保存到临时变量stu中。第2个from子句从表dtScore中查询成绩记录,并保存到临时遍历score中。Where子句则用于实现两个表之间的关联关系,即:成绩号(ScoreID)相等。最后select子句则表示要将表dtStu的Name字段和dtScore的Math、Chinese、English字段作为查询结果。

 

示例代码5-4

static void QueryStuScores( )

{

    DataSet ds = BuildDataSet( );                         //获取数据集ds

    DataTable dtStu = ds.Tables["Students"];              //从数据集ds中获取Students表dtStu

    DataTable dtScore = ds.Tables["Scores"];             //从数据集ds中获取Scores表dtScore

    var query1 =                                        //查询query1查询所有学生的成绩

        from stu in dtStu.AsEnumerable( )               //从Students表和Scores表中查询

        from score in dtScore.AsEnumerable( )

        where stu.Field<int>("ScoreID") == score.Field<int>("ScoreID") 

         //成绩编号(ScoreID)相等

       select new                                 //匿名类型为查询结果元素类型,包括四个成员

        {

            Name = stu.Field<string>("Name"),

            MathS = score.Field<int>("Math"),

            Chinese = score.Field<int>("Chinese"),

            English = score.Field<int>("English")

        };

    System.Console.WriteLine("Query1-所有学生成绩:");

    foreach (var item in query1)                         //打印查询query1的结果

    {

        System.Console.WriteLine("姓名:{0}, 数学:{1}, 语文:{2}, 英语:{3}",

            item.Name, item.MathS, item.Chinese, item.English);

    }

}

示例代码5-4的输出如下,从中可以看出学生“李四”没有成绩,所以不在查询query1的结果中。

Query1-所有学生成绩:

姓名:张三, 数学:80, 语文:75, 英语:78

姓名:王霞, 数学:88, 语文:80, 英语:60

姓名:赵敏, 数学:75, 语文:90, 英语:80

姓名:吴安, 数学:59, 语文:80, 英语:75

 

对于一些比较复杂的查询,仅使用一个LINQ查询很难实现,这就需要使用多个查询配合使用。比如现在需要查询没有成绩的学生的信息,该查询可以有两种方法实现,但都需要通过多个查询配合实现。

 

如示例代码5-5所示,query2查询采用第1种方法,首先查询scoreIDs得出表dtScore中所有的成绩号集合,然后query2在从表dtStu中找出所有学生中,成绩号不在查询scoreIDs中的学生,这些学生就是没有成绩的学生。

query3则采用第2种方法,首先查询scrStu通过两个并列的from子句,从表dtStu和dtScore中查询所有具有成绩的学生集合,和示例代码5-4中一样。然后query3通过方法语法的形式,通过Except()方法从所有学生信息中剔除具有成绩的学生,剩下就是没有成绩的学生。

 

示例代码5-5

static void QueryNoneScoreStu( )

{

    DataSet ds = BuildDataSet( );                  //获取数据集ds

    DataTable dtStu = ds.Tables["Students"];      //从数据集ds中获取Students表dtStu

    DataTable dtScore = ds.Tables["Scores"];      //从数据集ds中获取Scores表dtScore

    var scoreIDs =                               //查询scoreIDs查询所有有成绩的学生的成绩编号

        from score in dtScore.AsEnumerable( )

        select score.Field<int>("ScoreID");

   

var query2 =                          //查询query2查询所有成绩号不在查询scoreIDs中学生信息

        from stu in dtStu.AsEnumerable( )

        where !scoreIDs.Contains<int>(stu.Field<int>("ScoreID"))

        select stu;

    System.Console.WriteLine("Query2-没有成绩的学生:");

    foreach (var item in query2)                                   //打印查询query2的结果

    {

        System.Console.WriteLine("姓名:{0}, 性别:{1}, 年龄:{2}",

       item.Field<string>("Name"), item.Field<string>("XingBie"), item.Field<int>("Age"));

    }

    var scrStu =                                   //查询scrStu查询所有具有成绩信息的学生

        from stu in dtStu.AsEnumerable( )

        from score in dtScore.AsEnumerable( )

        where stu.Field<int>("ScoreID") == score.Field<int>("ScoreID")

        select stu;

   

 //查询query3是从所有学生记录中剔除具有成绩的学生。

    var query3 = dtStu.AsEnumerable( ).Except(scrStu);

    System.Console.WriteLine("Query3-没有成绩的学生:");

    foreach (var item in query3)                                   //打印查询query3的结果

    {

        System.Console.WriteLine("姓名:{0}, 性别:{1}, 年龄:{2}",

       item.Field<string>("Name"), item.Field<string>("XingBie"), item.Field<int>("Age"));

    }

}

 

示例代码5-5的输出如下所示,可以看出query2和query3虽然实现的方法不同,但是最终产生的查询结果都是一样,都给出了没有成绩的学生“李四”的详细信息。

Query2-没有成绩的学生:

姓名:李四, 性别:男, 年龄:19

Query3-没有成绩的学生:

姓名:李四, 性别:男, 年龄:19

 

技巧:从示例代码5-5中query2和query3可以看出,很多问题都可以有很多种不同的解决方法,但是最终结果都是一样,在解决问题时,也应该尽可能去寻找更多的解决办法,并从中选择最简单高效最适用的一种方法。另外,不要忘了方法语法在LINQ中的使用。

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3