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中的使用。

5.2.4 用查询创建数据表
LINQ to DataSet通过DataTableExtensions类提供的扩展方法CopyToDataTable()将从数据表中获取到的查询结果(类型为 IEnumerable<DataRow>)直接复制到一个新的数据表(DataTable)中,从而可以将查询结果绑定到界面控件(DataGridView等),也可以使用一些DataTable特有的特性。

CopyToDataTable()包括3个重载版本,定义如下,其中第1个版本最简单,也最常用。注意,这里的所有类型T都是DataRow类型及其子类。

public static DataTable CopyToDataTable<T>(

this IEnumerable<T> source) where T : DataRow

public static void CopyToDataTable<T>(

this IEnumerable<T> source,

DataTable table,

LoadOption options) where T : DataRow

public static void CopyToDataTable<T>(

this IEnumerable<T> source,

DataTable table,

LoadOption options,

FillErrorEventHandler errorHandler) where T : DataRow

其中,table表示目标数据表对象,用来保存数据。options用于指定DataTable的加载属性。errorHandler是一个函数委托,开发人员可以指定自定义的异常处理操作。CopyToDataTable()方法使用下面的过程通过查询创建DataTable复本:

(1)CopyToDataTable()方法克隆源表中的DataTable(实现IQueryable<T>接口的DataTable对象)。IEnumerable源通常来源于LINQ to DataSet表达式或方法查询。

(2)目标DataTable的架构从源表中第一个DataRow对象的列生成,克隆表的名称是源表的名称加上单词“query”。

(3)对于源表中的每一行,将行内容复制到新DataRow对象中,然后将该对象插入到目标DataTale中。

(4)复制完源表中所有DataRow对象后,返回克隆的DataTable。如果源序列不包含任何DataRow对象,则该方法将返回一个空DataTable。

示例代码5-6演示了CopyToDataTable()方法的使用,其中,查询query1查询所有既有成绩,年龄又大于20岁的学生信息,此时 query1类型为IEnumerable<DataRow>。然后使用query1的CopyToDataTable()方法创建一个 DataTable副本newDt,最后打印出newDt的数据。

示例代码5-6

static void UseCopyToDTSimple( )

{

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

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

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

var query1 =                                                              //查询query1年龄大于20且具有成绩的学生

from stu in dtStu.AsEnumerable( )

from score in dtScore.AsEnumerable( )

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

where (int)stu["Age"] > 20

select stu;

//通过CopyToDataTable()方法创建新的副本
    //然后打印该副本的信息

DataTable newDt = query1.CopyToDataTable<DataRow>( );

System.Console.WriteLine("学生列表:");

foreach (var item in newDt.AsEnumerable())    //打印该副本的信息

{

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

item["Name"], item["XingBie"], item["Age"]);

}

}

示例代码5-6的输出如下所示,可见query1的副本newDt所包含的数据和query1完全相同,注意本例中的数据源是示例代码5-3所生成。

学生列表:

姓名:王霞, 性别:女, 年龄:21

姓名:赵敏, 性别:女, 年龄:22

技巧:由于本例是控制台应用程序,所以只是简单打印newDt的记录,实际开发中CopyToDataTable()创建的副本,通常用于界面绑定。

5.2.5 修改表中字段数据
在前面章节的示例代码中,只是使用DataRowExtensions.Field()方法来获取数据表中字段的数据,当然LINQ to DataSet有时也需要对数据表中的数据进行修改,本节介绍如何使用SetField()修改数据。

在LINQ to DataSet中,DataRowExtensions类提供泛型扩展方法SetField(),用于设置数据表中指定列的数据,并且指定明确的数据类型。DataRowExtensions.SetField()方法具有3个重载版本,它们的定义如下所示:

public static void SetField<T>(

this DataRow row,

DataColumn column,

T value)

public static void SetField<T>(

this DataRow row,

int columnIndex,

T value)

public static void SetField<T>(

this DataRow row,

string columnName,

T value)

其中,column是表示要设置数据的列对象(DataColumn类型),columnIndex是从0开始的要设置数据的列索引,columnName是要设置数据的列名称。通常,一个数据表的列名是固定不变的,所以作者建议尽可能使用列名指定要设置数据的列,这样的代码更具扩展性。

示例代码5-7演示了SetField()方法的使用,通过BuildDataSet()方法获取数据表,第1个foreach语句遍历数据表的记录。通过SetField<int>()方法将学生的年龄增加2岁,因为学生年龄是int类型,所以SetField<T>()中的T 用int类型表示。最后,打印出数据表中所有的学生列表。

示例代码5-7

static void UseSetField( )

{

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

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

//遍历表dtStu中所有的学生,并通过SetField()方法将它们的年龄都增加2岁。

foreach (var row in dtStu.AsEnumerable())

{

int age = row.Field<int>("Age");

row.SetField<int>("Age", age + 2);

}

System.Console.WriteLine("学生列表:");

foreach (var item in dtStu.AsEnumerable( ))      //打印修改年龄后的学生信息

{

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

item["Name"], item["XingBie"], item["Age"]);

}

}

示例代码5-7的输出如下所示,从中可以看出,所有学生的年龄都被增加了2岁。

学生列表:

姓名:张三, 性别:男, 年龄:22

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

姓名:王霞, 性别:女, 年龄:23

姓名:赵敏, 性别:女, 年龄:24

姓名:吴安, 性别:男, 年龄:20

注意:SetField()方法是直接修改数据表中的记录,如果要保持原数据不变,那么在使用SetField()之前,应该先备份源数据表,作者建议通过CopyToDataTable()方法对源数据表进行备份。

5.2.6 使用数据视图DataView
数据视图(DataView)是常用的只读形式数据保存形式,可以将它绑定到UI界面,为用户提供形象动态的数据查阅功能。DataView本身可以从 DataTable或DataSet获取,除此之外,在.NET3.5中,还可以通过LINQ查询来获取DataView。

在LINQ to DataSet中,可以使用DataTableExtensions.AsDataView()扩展方法从DataTable或LINQ查询创建一个与数据源对应的DataView对象。AsDataView()方法包括2个重载版本,定义如下,它们只是扩展的目标类型不同(即:数据源不同)。

public static DataView AsDataView(

this DataTable table

)

public static DataView AsDataView<T>(

this EnumerableRowCollection<T> source

) where T : DataRow

AsDataView()第2个重载版本中,需要EnumerableRowCollection<DataRow>类型的数据源,该类型表示从LINQ查询返回的DataRow对象集合,可以从LINQ查询获取。

示例代码5-8演示了AsDataView()方法的使用。其中,BuildDataSet()只是用来创建数据源,不再赘述。 CreateDataView()方法中,dvDt是通过DataTable类的扩展方法AsDataView()创建DataView,该 DataView中包含数据表中所有的数据记录。其中,查询query1、query2、query3都是LINQ to DataSet查询,并且明确类型为EnumerableRowCollection<DataRow>,当然这里也可以用var可变类型,编译器会自动转换。

示例代码5-8

static DataSet BuildDataSet( )

{

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

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

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

DataTable dtStu = new DataTable("Students");

ds.Tables.Add(dtStu);

//添加学生信息记录的列(字段)信息,包括3个字段:

//姓名:Name,string类型

//性别:XingBie,string类型

//年龄:Age,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")),

});

//添加学生信息的行信息,包括:姓名、性别和年龄

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

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

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

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

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

dtStu.Rows.Add("杨花", "女", 23);

return ds;                                                                    //返回数据集

}

static void CreateDataVeiw( )

{

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

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

//用DataTable.AsDataView()方法从数据表dt创建DataView对象dvDt

DataView dvDt = dt.AsDataView( );

//query1用LINQ查询创建DataView对象dvDt,查询它所有的元素

EnumerableRowCollection<DataRow> query1 =

from stu in dt.AsEnumerable( )

select stu;

DataView dvNml = query1.AsDataView( );                  //获取查询query1产生的DataView

//query2用LINQ查询创建具有过滤信息的DataView,查询所有姓“杨”的学生

EnumerableRowCollection<DataRow> query2 =

from stu in dt.AsEnumerable( )

where stu.Field<string>("Name").StartsWith("杨")

select stu;

DataView dvFilter = query2.AsDataView( );      //获取查询query2产生的DataView

//query3用LINQ查询创建具有排序信息的DataView,将学生按照从小到大的顺序排序

EnumerableRowCollection<DataRow> query3 =

from stu in dt.AsEnumerable( )

orderby stu.Field<int>("Age")

select stu;

DataView dvSort = query3.AsDataView( );        //获取查询query3产生的DataView

}

很多场合都需要对数据进行排序和过滤操作,在LINQ to DataSet中有两种方法完成这样的操作,一是通过具有排序和过滤操作得到的LINQ查询创建DataView。如示例代码5-8中的dvFilter 和dvSort,前者通过具有where子句过滤功能的查询query2创建,后者通过具有orderby子句排序功能的查询query3创建,dvFilter和dvSort所得到的数据自然是过滤和排序之后的数据集合。另外一种方法是通过DataView类的RowFilter和Sort 属性分别进行过滤和排序操作,这两个属性都是字符串(string)类型。

RowFilter属性接收一个表示过滤条件的字符串,格式为:指定列的名称后跟一个运算符和一个要筛选的值。运算符可以是:等于(=)、大于(>)、小于(<)等。通过设置RowFilter属性的值,有两种不同的方式清除DataView上的过滤条件:

q      将RowFilter属性设置为null。

q      将RowFilter属性设置为一个空字符串。Sort属性接收一个表示排序信息的字符串,它包含列名,后跟“ASC”(升序)或“DESC”(降序)。在默认情况下列按升序排序,多个列可用逗号隔开。清除DataView中的排序信息也有两种方式:

q      将Sort属性设置为null。

q      将Sort属性设置为一个空字符串。

示例代码5-9演示了RowFilter和Sort属性的使用,DataView对象dvDt是直接从DataTable对象dtStu创建而来,包含 dtStu中的所有记录。其中RowFilter设置为“Age>20”表示只需要Age字段大于20的记录。Sort设置为“Age asc, Name desc”表示先按照Age字段从低到高排序,后按照姓名从高到低排序。

示例代码5-9

static void UseDataView( )

{

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

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

//用DataTable.AsDataView()方法从数据表dt创建DataView对象dvDt

DataView dvDt = dt.AsDataView( );

//通过RowFilter属性设置DataView过滤信息,只需要年龄大于20岁的学生记录

dvDt.RowFilter = "Age > 20";

//设置RowFilter为null或空字符串,清除过滤信息,二选一

dvDt.RowFilter = string.Empty;

dvDt.RowFilter = null;

//通过Sort属性设置DataView排序信息,年龄从小到大排序,姓名从大到小排序

dvDt.Sort = "Age asc, Name desc";

//设置RowFilter为null或空字符串,清除过滤信息,二选一

dvDt.Sort = string.Empty;

dvDt.Sort = null;

}

从上面示例代码可以看出,通过LINQ to DataSet查询和DataView的RowFilter、Sort属性都可以进行排序和过滤。但是LINQ查询提供的排序和过滤功能更加强大,开发人员可以编写自定义的过滤函数、排序方法等。而RowFilter和Sort属性只能是基于字段的表达式,只能实现简单的排序和过滤,由于可以清除,所以更为灵活。

技巧:当DataView要显示的数据比较复杂,需要进行复杂的过滤或排序操作时,建议使用LINQ查询来创建DataView,作为最终或临时视图。然后使用RowFilter和Sort属性进行DataView灵活的排序和筛选操作。

转载于:https://www.cnblogs.com/hxwzwiy/archive/2012/03/26/2418611.html

LINQ to DataSet实现复杂数据查询【下】相关推荐

  1. C# 3.0通过Linq、Lambda、匿名函数、代理函数实现数据查询

    这几天,正在学习Linq.Lambda,做了些实验,通过Linq.Lambda.匿名函数.代理函数4种方式实现一个简单的查询,把实现结果记录一下,以免忘记.       这段代码中有一个Person类 ...

  2. Dataset之图片数据增强:设计自动生成汽车车牌图片算法(cv2+PIL)根据随机指定七个字符生成逼真车牌图片数据集(自然场景下+各种噪声效果)可视化

    Dataset之图片数据增强:设计自动生成汽车车牌图片算法(cv2+PIL)根据随机指定七个字符生成逼真车牌图片数据集(自然场景下+各种噪声效果)可视化 导读 设计自动生成汽车车牌图片算法,基于cv2 ...

  3. 安卓 spinner下拉框 做模糊查询_SEO数据查询工具

    SEO数据查询工具是SEO工作中使用最频繁的工作,最常用的是站长之家(http://tool.chinaz.com/)以及爱站(http://www.aizhan.com/)的查询.这里主要介绍站长之 ...

  4. sql语句查询一条数据的上一条数据和下一条数据

    表t_tablename id_param为当前id 1.查询上一条数据 select * from t_tablename where id=(select max(id) from t_table ...

  5. 大数据量下 PageHelper 分页查询性能问题的解决办法

    作者:岁月安然 blog.csdn.net/baidu_38083619/article/details/82463058 前因 项目一直使用的是PageHelper实现分页功能,项目前期数据量较少一 ...

  6. Pro LINQ 之三:LINQ to DataSet

    写在前面 将LINQ to DataSet单独放一篇,是因为随后的LINQ to SQL默认只支持MS SQL Server.只有LINQ to DataSet能在没有相应Data Provider帮 ...

  7. .NET应用架构设计—面向查询服务的参数化查询设计(分解业务点,单独配置各自的数据查询契约)...

    阅读目录: 1.背景介绍 2.对业务功能点进行逻辑划分(如:A.B.C分别三个业务点) 2.1.配置映射关系,对业务点配置查询契约(构造VS插件方便生成查询契约) 2.2.将配置好的映射策略文件放在调 ...

  8. 开源大数据查询分析引擎

    引言 大数据查询分析是云计算中核心问题之一,自从Google在2006年之前的几篇论文奠定云计算领域基础,尤其是GFS.Map-Reduce.Bigtable被称为云计算底层技术三大基石.GFS.Ma ...

  9. C# LINQ系列:LINQ to DataSet的DataTable操作 及 DataTable与Linq相互转换

    LINQ to DataSet需要使用System.Core.dll.System.Data.dll和System.Data.DataSetExtensions.dll,在项目中添加引用System. ...

最新文章

  1. AutoFac使用方法总结:Part I
  2. 一个小灯泡引发大论战:千万粉丝科普up主翻车,伊朗“唐马儒”、李永乐等下场,30万公里导线引百万网友围观...
  3. (FCN)-Fully Convolutional Networks for Semantic Segmentation
  4. 《构建之法》读后感之项目计划
  5. 动态规划矩阵连乘问题
  6. SAP UI5 应用开发教程之三十一 - SAP UI5 的路由历史和路由回退(Routing back and history)试读版
  7. IOS开发CAKeyframeAnimation的基本使用与keypath的列举
  8. Apache JMeter:随心所欲进行负载测试
  9. Android 代码实现查看SQLite数据库中的表
  10. 爬虫-14-利用代理爬取数据
  11. java canvas 动态画图_canvas前端动图如何实现
  12. 算法导论笔记:32字符串匹配算法
  13. amp mysql升级_【简单的案例分享,停机10分钟】10204升级CRSamp;amp;DB的PSU至1
  14. nginx作为静态资源服务器的配置
  15. jquery.form.js实现将form提交转为ajax方式提交的使用方法
  16. jquery ajax jsonp跨域调用实例代码
  17. HDU1465_递推_错排
  18. 教你计算三种分子性质的方法
  19. Conficker.AE病毒局域网扫描工具
  20. 井字游戏 Tic Tac Toe

热门文章

  1. Redis与数据库的爱恨纠葛
  2. 新安装Ubuntu16.04无法连接无线有线网络的问题(第一更)
  3. 腾讯课堂下载回放视频
  4. 千万融资与联合国接见 移动社交Blued背后技术支持
  5. 最流行的经典爱情语句
  6. linux ctg重装,Linux 下从头再走 GTK+-3.0 (五)
  7. 一个论坛看到的签名,我把它取名为:“一长两短”
  8. 相机标定究竟在标定什么?
  9. php转义还原,PHP中addslashes()和stripslashes()实现字符串转义和还原用法实例_php技巧...
  10. java经典问题总结