写在前面

将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相关推荐

  1. 【LINQ】LINQ 简介

    LINQ基本概念 LINQ(语言集成查询) 是Language Integrated Query的简称,它是集成在.NET编程语言中的一种特性.已经成为了编程语言的组成部分,在编程时可以进行语法检查, ...

  2. Linq技术四:动态Linq技术 -- Linq.Expressions

    前面介绍了Linq的三个方面应用:Linq to SQL, Linq to XML和Linq to Object,这篇介绍一下动态Linq的实现方式及应用场景. 命名空间: System.Linq; ...

  3. 综合应用WPF/WCF/WF/LINQ之三:采用用代码创建的方式实现CheckListBox的CustomControl

    以我们的Eallies OA系统为例,实现PageBase的方法如下: 1.在Eallies.OA.UI.Controls.Logical项目中添加一个纯的Class,并让其继承于System.Win ...

  4. 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 ...

  5. 【LINQ】Linq to SQL -- Count/Sum/Min/Max/Avg 操作符

    适用场景 统计数据,比如统计一些数据的个数,求和.最小值.最大值.平均数 Count 说明:返回集合中的元素个数,返回Int类型:不延迟.生成SQL语句为:SELECT COUNT(*) FROM 1 ...

  6. 【LINQ】Linq to SQL -- Where语句

    简介 作用:Where在SQL查询语句中起到了查询.过滤的作用,在LINQ语句中也是相似的. 3种形式:简单形式.关系条件式.First()形式. 举例 一.简单形式 1.使用where筛选性别为女的 ...

  7. 【LINQ】Linq to SQL -- Select语句

    简介 # 作用:查询 # 说明:和SQL命令中的select作用相似,但位置不同.查询表达式中的select及所接句子是放在表达式最后,并把句子中的变量也就是结果返回回来:延迟. # 9种形式:Sel ...

  8. LINQ系列:LINQ to ADO.NET概述

    LINQ to ADO.NET 包括两种独立的技术: LINQ to DataSet 和 LINQ to SQL. 使用 LINQ to DataSet 可以对DataSet 执行丰富而优化的查询,而 ...

  9. Linq的简介和基础知识学习

    学习LINQ之前,我们要知道LINQ是干什么,解决什么问题的,怎样学习? 一.LINQ简介 1.什么是LINQ? 什么是LINQ?LINQ中文翻译为语言集成查询(Language Integrated ...

最新文章

  1. FreeBSD控制台分辨率调整
  2. 自己实现一个最简单的数据库
  3. 3.1 哈尔空间 V0
  4. arraylist 后往前遍历_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector
  5. Linux命令之文件处理
  6. 关于CTeX的几个大坑
  7. 图书管理员【2017年普及组第二题】
  8. JDK源码学习笔记——Enum枚举使用及原理
  9. 学java里面包括php_【学习java和PHP区别你知道多少】
  10. 希捷服务器硬盘格式化不了,希捷硬盘专用分区格式化Seagate DiscWizard16.0 官方版...
  11. No version of NDK matched the requested version xxx 问题解决
  12. linux vim命令详解 编辑文件 保存 退出
  13. OC block的回环引用
  14. Spark数据倾斜解决
  15. 11行Python代码制作聊天机器人
  16. 关于APP个人信息安全和隐私合规评估,你想知道的都在这!
  17. 学校食堂外卖APP开发模板
  18. pdb、dmp调试文件
  19. 【RT-ThreadART-PI】RGB565_LCD显示屏的使用
  20. msn空间中使用电子邮件发日志项和添加音乐播放模块

热门文章

  1. html退出登录_[实战小剧场servletamp;jsp] 用户登录及退出功能实现
  2. Python 循环拼接字符串_详解Python拼接字符串的七种方式
  3. php。defined,PHP defined()函数的使用图文详解
  4. linux设置数据库定时备份,linux中使用计划任务进行数据库定期备份
  5. C#获取当前进程、项目路径的方法
  6. C++对象模型5——类对象的内存布局
  7. 打开word文档提示文件未找到_word图片显示:如何打开多图文档不再卡慢
  8. 一蹴而就的解释是什么_聪明的孩子喜欢问“为什么”,还是喜欢问“为什么”让孩子聪明?...
  9. centos7通过yum升级内核到最新版本
  10. Win10 无需安装虚拟机/双系统使用 linux