Pro LINQ 之三:LINQ to DataSet
写在前面
将LINQ to DataSet单独放一篇,是因为随后的LINQ to SQL默认只支持MS SQL Server。只有LINQ to DataSet能在没有相应Data Provider帮助的情况下,与其他数据库平台进行交互。而且LINQ to DataSet中的许多基本概念,是引导我们深入LINQ to SQL以及Entity Framework的基础。
P341 DataRow的集合运算符
通过LINQ与数据库交互,仍需要LINQ的三个基本要素:DataTable是序列,DataRow是元素,以及相关的操作符。
但是DataRow与Object的显著区别在于如何唯一性地标识一个DataRow。Object可以通过GetHashCode()来保证其被唯一性地识别,而DataRow只会导致引用Reference间的比较,而这并不是我们所期望的。因为不同时刻我们从数据库中加载的同一条DataRow,可能对应完全不同的引用。为此,在DataRow的LINQ运算符中,出现了一个默认的比较器DataRowComparer.Default。使用的方式与LINQ to Objects一致:
DataTable dt = new DataTable(); IEnumerable<DataRow> except = dt.AsEnumerable().Except(subtable, DataRowComparer.Default);
有了DataRowComparer.Default的帮助,当我们把IQueryable接口的DataTable利用AsEnumerable()转换为IEnumerable<>后,即可采取类似LINQ to Objects的运算符进行操作了。如果没有DataRowComparer.Default,则会在DataRow的对象筛选时得到出乎意料的结果。
需要说明的是,DataRowComparer<T>是对应的泛型。可以自由定制自己的DataRow比较子。
P353 DataRow的Field运算符
问题来源于下面这样的一种情形:
string anthonysClass = (from s in seq1where s.Field<string>("Name") == "Anthony Adams"from c in seq2where c["Id"] == s["Id"]select (string) c["Class"]).SingleOrDefault<string>();
由于DataRow[列名]的引用,本来是int类型的列值返回后被装箱成为object,其中的c["Id"] == s["Id"]将是两个object之间的比较,从而导致结果错误。当我们将比较条件修改为(int) c["Id"] == (int) s["Id"]之后,才能返回正确的结果。但从另一个方面考虑,当该字段值为DBNull时(int)c["Id"]这样的强制类型转换便不再有效,因此引入了Field<>运算符。需要说明的是,Field<>取出的值有可能是null。
其存在三种引用方式:
row.Field<字段值类型>(列序号) | row.Field<int>(0) |
row.Field<字段值类型>(列名) | row.Field<int>(“Id”) |
row.Field<字段值类型>(Column引用) | row.Field<int>(dt.Columns[0]) |
同时,还引入了Field<>的DataRowVersion,这与ADO.NET中的DataRowState是相互呼应的。
Original | 取原始值 |
Current | 取当前值 |
Proposed | 取建议值 |
Default |
Added、Modified或Current=>Delete Detached=>Proposed |
例如这样:
int id = (from s in seq1where s.Field<string>("Name") == "Anthony Adams"select s.Field<int>("Id", DataRowVersion.Current)).SingleOrDefault<int>();
P362 DataRow的SetField<T>运算符
SetField<>(列, 值),其中列的引用方式同Field<>。不同于Field<>的,是null值将可能引发DBNull异常。
特别是对于string类型的列,由于不支持string? name这样的可空声明,因此要特别注意处理,避免陷入DBNull异常。
(from s in seq1where s.Field<string>("Name") == "Michael Bluth"select s).Single<DataRow>().SetField("Name", "Tony Wonder");
P365 DataTable相关运算符
AsEnumerable()相对简单,稍微复杂一点的是CopyToDataTable()。后者有一个类似于DataRowState的LoadOption选择方式。每个列,都有Current与Original两个版本的数据。这个LoadOption决定哪个版本的数据被拷贝到新的DataTable中。
OverwriteChanges | Current与Original都拷贝 |
PreserveChanges | 只拷贝Original |
Upsert | 只拷贝Current |
一个需要考虑的情形是,在没有定义新表主键的情况下,在利用DataTable.AcceptChanges()将所有DataRow的State复位之前,如果象下面这样执行2次CopyToDataTable(),将会导致DataRow被重复添加。其中第2次拷贝的DataRow将没有Original版本。
Console.WriteLine("Before upserting DataTable:"); foreach (DataRow dataRow in newTable.AsEnumerable()) {Console.WriteLine("Student Id = {0} : original {1} : current {2}",dataRow.Field<int>("Id"),dataRow.Field<string>("Name", DataRowVersion.Original),dataRow.Field<string>("Name", DataRowVersion.Current)); }(from s in dt1.AsEnumerable() where s.Field<string>("Name") == "Anthony Adams" select s).Single<DataRow>().SetField("Name", "George Oscar Bluth");dt1.AsEnumerable().CopyToDataTable(newTable, LoadOption.Upsert);Console.WriteLine("{0}After upserting DataTable:", System.Environment.NewLine); foreach (DataRow dataRow in newTable.AsEnumerable()) {Console.WriteLine("Student Id = {0} : original {1} : current {2}",dataRow.Field<int>("Id"),dataRow.HasVersion(DataRowVersion.Original) ?dataRow.Field<string>("Name", DataRowVersion.Original) : "-does not exist-",dataRow.Field<string>("Name", DataRowVersion.Current)); }
运行结果:
--------------------------------------------------------------- Before upserting DataTable: Student Id = 1 : original Joe Rattz : current Joe Rattz Student Id = 7 : original Anthony Adams : current Anthony Adams Student Id = 13 : original Stacy Sinclair : current Stacy Sinclair Student Id = 72 : original Dignan Stephens : current Dignan Stephens After upserting DataTable: Student Id = 1 : original Joe Rattz : current Joe Rattz Student Id = 7 : original Anthony Adams : current Anthony Adams Student Id = 13 : original Stacy Sinclair : current Stacy Sinclair Student Id = 72 : original Dignan Stephens : current Dignan Stephens Student Id = 1 : original -does not exist- : current Joe Rattz Student Id = 7 : original -does not exist- : current George Oscar Bluth Student Id = 13 : original -does not exist- : current Stacy Sinclair Student Id = 72 : original -does not exist- : current Dignan Stephens ---------------------------------------------------------------
因此,指定新表的主键是必要的。就象下面这样:
DataTable newTable = dt1.AsEnumerable().CopyToDataTable(); newTable.PrimaryKey = new DataColumn[] { newTable.Columns[0] };
不知道列的基本特征、约束等会否一并被Copy?待解!
P373 LINQ to 类型化DataSet
类型化DataSet,基于编译时的类型检查和直观的表、列引用语法等优势,曾经是NET 2.0时代数据库应用的利器。但受限于其Cache的特性,和缺乏一致的查询机制,在N层应用中上下穿梭的能力有限,逐渐被新兴的LINQ与Entity所取代。但在小型的数据库应用中,DataSet仍有一定的生存空间。
string name = studentsDataSet.Students.Where(student => student.Id == 7).Single().Name;
特别要提的是,类SQL语法的形式与扩展方法调用的形式相比较,仍是后者的效能胜出。
[LINQ] Pro LINQ 之四:LINQ to SQL
转载于:https://www.cnblogs.com/Abbey/archive/2011/07/14/2106771.html
Pro LINQ 之三:LINQ to DataSet相关推荐
- 【LINQ】LINQ 简介
LINQ基本概念 LINQ(语言集成查询) 是Language Integrated Query的简称,它是集成在.NET编程语言中的一种特性.已经成为了编程语言的组成部分,在编程时可以进行语法检查, ...
- Linq技术四:动态Linq技术 -- Linq.Expressions
前面介绍了Linq的三个方面应用:Linq to SQL, Linq to XML和Linq to Object,这篇介绍一下动态Linq的实现方式及应用场景. 命名空间: System.Linq; ...
- 综合应用WPF/WCF/WF/LINQ之三:采用用代码创建的方式实现CheckListBox的CustomControl
以我们的Eallies OA系统为例,实现PageBase的方法如下: 1.在Eallies.OA.UI.Controls.Logical项目中添加一个纯的Class,并让其继承于System.Win ...
- Advanced Linq - Dynamic Linq query library: Add support for 'Contains' extension
原文链接: http://blog.walteralmeida.com/2010/05/advanced-linq-dynamic-linq-library-add-support-for-conta ...
- 【LINQ】Linq to SQL -- Count/Sum/Min/Max/Avg 操作符
适用场景 统计数据,比如统计一些数据的个数,求和.最小值.最大值.平均数 Count 说明:返回集合中的元素个数,返回Int类型:不延迟.生成SQL语句为:SELECT COUNT(*) FROM 1 ...
- 【LINQ】Linq to SQL -- Where语句
简介 作用:Where在SQL查询语句中起到了查询.过滤的作用,在LINQ语句中也是相似的. 3种形式:简单形式.关系条件式.First()形式. 举例 一.简单形式 1.使用where筛选性别为女的 ...
- 【LINQ】Linq to SQL -- Select语句
简介 # 作用:查询 # 说明:和SQL命令中的select作用相似,但位置不同.查询表达式中的select及所接句子是放在表达式最后,并把句子中的变量也就是结果返回回来:延迟. # 9种形式:Sel ...
- LINQ系列:LINQ to ADO.NET概述
LINQ to ADO.NET 包括两种独立的技术: LINQ to DataSet 和 LINQ to SQL. 使用 LINQ to DataSet 可以对DataSet 执行丰富而优化的查询,而 ...
- Linq的简介和基础知识学习
学习LINQ之前,我们要知道LINQ是干什么,解决什么问题的,怎样学习? 一.LINQ简介 1.什么是LINQ? 什么是LINQ?LINQ中文翻译为语言集成查询(Language Integrated ...
最新文章
- FreeBSD控制台分辨率调整
- 自己实现一个最简单的数据库
- 3.1 哈尔空间 V0
- arraylist 后往前遍历_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector
- Linux命令之文件处理
- 关于CTeX的几个大坑
- 图书管理员【2017年普及组第二题】
- JDK源码学习笔记——Enum枚举使用及原理
- 学java里面包括php_【学习java和PHP区别你知道多少】
- 希捷服务器硬盘格式化不了,希捷硬盘专用分区格式化Seagate DiscWizard16.0 官方版...
- No version of NDK matched the requested version xxx 问题解决
- linux vim命令详解 编辑文件 保存 退出
- OC block的回环引用
- Spark数据倾斜解决
- 11行Python代码制作聊天机器人
- 关于APP个人信息安全和隐私合规评估,你想知道的都在这!
- 学校食堂外卖APP开发模板
- pdb、dmp调试文件
- 【RT-ThreadART-PI】RGB565_LCD显示屏的使用
- msn空间中使用电子邮件发日志项和添加音乐播放模块
热门文章
- html退出登录_[实战小剧场servletamp;jsp] 用户登录及退出功能实现
- Python 循环拼接字符串_详解Python拼接字符串的七种方式
- php。defined,PHP defined()函数的使用图文详解
- linux设置数据库定时备份,linux中使用计划任务进行数据库定期备份
- C#获取当前进程、项目路径的方法
- C++对象模型5——类对象的内存布局
- 打开word文档提示文件未找到_word图片显示:如何打开多图文档不再卡慢
- 一蹴而就的解释是什么_聪明的孩子喜欢问“为什么”,还是喜欢问“为什么”让孩子聪明?...
- centos7通过yum升级内核到最新版本
- Win10 无需安装虚拟机/双系统使用 linux