LINQ To DataSet
2008-04-08 17:34
211 查看
LINQ To DataSet
LazyBee
LINQ to DataSet主要是提供对离线数据的支持,只有在填充DataSet之后,我们才能使用LINQ to DataSet来查询数据。其功能主要是通过System.Data.DataRowExtions和System.Data.DataTableExtensions两个静态类中的扩展方法来公开的。LINQ to DataSet是LINQ to ADO.Net中的一部分,但这部分所占比重非常小,内容也比较少。下面就让我们首先来看看DataTableExtensions中的扩展方法:
public static EnumerableRowCollection<DataRow> AsEnumerable(this DataTable source)
----------------------------------------------------------------------------------------------------
public static DataView AsDataView(this DataTable table)
public static DataView AsDataView<T>(this EnumerableRowCollection<T> source) where 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
从定义中就可以看出这三类主要是提供DataTable、DataView和IEnumerable<TRow>三者之间的转换。大家都知道LINQ to Object查询主要是对IEnumerable<T>序列进行的操作,这样就使得DataTable、DataView和LINQ之间建立了一个转换桥梁。
因此,在我们需要将DataTable应用于LINQ to DataSet查询是要先调用AsEnumerable完成DataTable到LINQ的转换。如果我们需要将LINQ to DataSet的查询的结果进行数据绑定时我们需要调用AsDataView<T>的泛型版来完成LINQ到DataView的转换。当然我们也可以使用CopyToDataTable来进行LINQ到DataTable的转换。
注意:如果在我们完成了DataTable到LINQ(IEnumerable<DataRow>)的转换之后(也就是调用AsEnumerable扩展方法),需要进行两个DataRow序列的集合操作如Distinct,Union,Except,Intersect,SequenceEqual,这些操作都需要对数据源中的元素进行相等比较,由于缺省情况下都是调用数据源中的元素的GetHashCode和Equals操作来判断的,对于DataRow而言就是判断对象的引用是否相等,这样可能会导致我们不期望的结果(DataRow里面的数据内容是相同的,但不是同一个对象),所以我们要使用Distinct,Union,Except,Intersect,SequenceEqual带IEqualityComparer的重载版本,使用System.Data.DataRowComparer.Default作为参数。这个比较器类是.Net3.5专门为LINQ to DataSet新增加的,用于比较DataRow的值的,它是通过先比较DataColumn的数量,然后使用该列中类型的Equals方法进行比较。
不带LoadOptions参数的CopyToDataTable方法将自动为每一行的每一个字段创建(更新)原始版本和当前版本,带有LoadOptions参数的CopyToDataTable重载版本可以让你指定是创建(更新)原始版本或是当前版本,或者两者都填充。LoadOptions选项有下面三个选项值可以选择:
OverwriteChanges: 创建(更新)每一列的当前值和原始值
PreserveChanges: 创建(更新)每一列的原始值
Upset: 创建(更新)每一列的当前值
接下来,让我们来看看DataRowExtensions中的扩展方法。在这个DataRowExtensions中的扩展方法主要是从数据行中获得字段的值(泛型的Field方法)和设置数据行中字段的值(泛型的SetField方法)。
public static T Field<T>(this DataRow row,DataColumn column)
public static T Field<T>(this DataRow row,int columnIndex)
public static T Field<T>(this DataRow row,string columnName)
public static T Field<T>(this DataRow row,DataColumn column,DataRowVersion version)
public static T Field<T>(this DataRow row,int columnIndex,DataRowVersion version)
public static T Field<T>(this DataRow row,string columnName,DataRowVersion version)
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)
其中,row: 是我们要使用的数据行对象实例
column: 指定要返回(设置)其值的列
columnIndex: 指定要返回(设置)其值的列的索引
columnName: 指定要返回(设置)其值的列名
value: 要设置的新值,如果是null,将自动转换为DBNull.Value
version: 要获取的数据行的版本
下面,我们就来看看一个使用LINQ to DataSet的实例,这个例子主要描述了一下上面扩展方法的用法,同时给出了部分注意的事项:
public static class LINQToDataSet
例子中有比较详尽的注释,相信大家看应该没有什么问题。关于C#3.0的相关语法,大家可以参考我以前的随笔(C# 3.0 之新特性总结)。
这个例子的输出结果为:
We try to get access to original version, so we will get the exception.:
================================================================
Exception:There is no Original data to access.
================================================================
We will use CopyToDataTable to build original version.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call SetField to change name.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current George Oscar Bluth
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call SetField to change name to null.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call CopyToDataTable.We will not get our expected result because we have not set primary key.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original :current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call Distinct.We will not get our expected result because we have not used DatarowComparer.Default comparer.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original :current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call Distinct.this is what we want.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
Student Id = 13 :original :current
================================================================
After call CopyToDataTable.this is what we want.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original :current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
总结,在使用LINQ to DataSet的时候需要注意以下几个方面:
1 在对IEnumeralbe<DataRow>进行数据行的集合操作如Distinct, Except, Union, Intersect,
SequenceEqual时,需要使用System.Data.DatarowComparer.Default作为比较器作为输入参数,以保证对DataRow是进行值比较,而不是引用比较。当然,如果GroupBy或者其他操作的key的类型是DataRow时,也需要使用此比较器,以使我们得到我们期望的行为。
2 SetField可以将字段值设置为null,并且SetField方法将自动将其转换为DBNull.Value.
3 Field可以完成从DBNull.Value到null的转换。也就是说,如果该字段的值是DBNull.Value
时,Field方法将自动将其转为null并返回。这个方法是强类型的,不需要象通过列名或者列索引返回字段值一样将Object类型进行造型成需要的类型(值类型进行拆箱操作),(如果字段的值是DBNull.Value时进行造型还将导致抛出异常)Field扩展方法自动做了这些处理,省去了开发人员手动进行这些处理的麻烦。
4 缺省情况下,数据行的Original版本中是没有值的,试图访问时将导致异常发生。当然,
可以在访问之前使用DataRow.HasVersion来进行判断,以防止异常的发生。也可以通过调用DataRow.AcceptChanges方法来建立Original版本来避免异常的发生。不带LoadOptions参数的CopyToDataTable扩展方法也会为返回的DataTable自动建立DataRow的Original和Current版本.
5 当使用带LoadOptions输入参数的CopyToDataTable扩展方法时,必须为目标DataTable指定主键列,否则,该函数只是将源DataTable追加到目标DataTable的最后面。可能达不到期望更新的结果。
LazyBee
LINQ to DataSet主要是提供对离线数据的支持,只有在填充DataSet之后,我们才能使用LINQ to DataSet来查询数据。其功能主要是通过System.Data.DataRowExtions和System.Data.DataTableExtensions两个静态类中的扩展方法来公开的。LINQ to DataSet是LINQ to ADO.Net中的一部分,但这部分所占比重非常小,内容也比较少。下面就让我们首先来看看DataTableExtensions中的扩展方法:
public static EnumerableRowCollection<DataRow> AsEnumerable(this DataTable source)
----------------------------------------------------------------------------------------------------
public static DataView AsDataView(this DataTable table)
public static DataView AsDataView<T>(this EnumerableRowCollection<T> source) where 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
从定义中就可以看出这三类主要是提供DataTable、DataView和IEnumerable<TRow>三者之间的转换。大家都知道LINQ to Object查询主要是对IEnumerable<T>序列进行的操作,这样就使得DataTable、DataView和LINQ之间建立了一个转换桥梁。
因此,在我们需要将DataTable应用于LINQ to DataSet查询是要先调用AsEnumerable完成DataTable到LINQ的转换。如果我们需要将LINQ to DataSet的查询的结果进行数据绑定时我们需要调用AsDataView<T>的泛型版来完成LINQ到DataView的转换。当然我们也可以使用CopyToDataTable来进行LINQ到DataTable的转换。
注意:如果在我们完成了DataTable到LINQ(IEnumerable<DataRow>)的转换之后(也就是调用AsEnumerable扩展方法),需要进行两个DataRow序列的集合操作如Distinct,Union,Except,Intersect,SequenceEqual,这些操作都需要对数据源中的元素进行相等比较,由于缺省情况下都是调用数据源中的元素的GetHashCode和Equals操作来判断的,对于DataRow而言就是判断对象的引用是否相等,这样可能会导致我们不期望的结果(DataRow里面的数据内容是相同的,但不是同一个对象),所以我们要使用Distinct,Union,Except,Intersect,SequenceEqual带IEqualityComparer的重载版本,使用System.Data.DataRowComparer.Default作为参数。这个比较器类是.Net3.5专门为LINQ to DataSet新增加的,用于比较DataRow的值的,它是通过先比较DataColumn的数量,然后使用该列中类型的Equals方法进行比较。
不带LoadOptions参数的CopyToDataTable方法将自动为每一行的每一个字段创建(更新)原始版本和当前版本,带有LoadOptions参数的CopyToDataTable重载版本可以让你指定是创建(更新)原始版本或是当前版本,或者两者都填充。LoadOptions选项有下面三个选项值可以选择:
OverwriteChanges: 创建(更新)每一列的当前值和原始值
PreserveChanges: 创建(更新)每一列的原始值
Upset: 创建(更新)每一列的当前值
接下来,让我们来看看DataRowExtensions中的扩展方法。在这个DataRowExtensions中的扩展方法主要是从数据行中获得字段的值(泛型的Field方法)和设置数据行中字段的值(泛型的SetField方法)。
public static T Field<T>(this DataRow row,DataColumn column)
public static T Field<T>(this DataRow row,int columnIndex)
public static T Field<T>(this DataRow row,string columnName)
public static T Field<T>(this DataRow row,DataColumn column,DataRowVersion version)
public static T Field<T>(this DataRow row,int columnIndex,DataRowVersion version)
public static T Field<T>(this DataRow row,string columnName,DataRowVersion version)
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)
其中,row: 是我们要使用的数据行对象实例
column: 指定要返回(设置)其值的列
columnIndex: 指定要返回(设置)其值的列的索引
columnName: 指定要返回(设置)其值的列名
value: 要设置的新值,如果是null,将自动转换为DBNull.Value
version: 要获取的数据行的版本
下面,我们就来看看一个使用LINQ to DataSet的实例,这个例子主要描述了一下上面扩展方法的用法,同时给出了部分注意的事项:
public static class LINQToDataSet
例子中有比较详尽的注释,相信大家看应该没有什么问题。关于C#3.0的相关语法,大家可以参考我以前的随笔(C# 3.0 之新特性总结)。
这个例子的输出结果为:
We try to get access to original version, so we will get the exception.:
================================================================
Exception:There is no Original data to access.
================================================================
We will use CopyToDataTable to build original version.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call SetField to change name.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current George Oscar Bluth
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call SetField to change name to null.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call CopyToDataTable.We will not get our expected result because we have not set primary key.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original :current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call Distinct.We will not get our expected result because we have not used DatarowComparer.Default comparer.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original :current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
After call Distinct.this is what we want.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original PiPi Zhu:current PiPi Zhu
Student Id = 72 :original Chong Chong:current Chong Chong
Student Id = 13 :original :current
================================================================
After call CopyToDataTable.this is what we want.
================================================================
Student Id = 1 :original Lazy Bee:current Lazy Bee
Student Id = 7 :original Flying Wind:current Flying Wind
Student Id = 13 :original :current
Student Id = 72 :original Chong Chong:current Chong Chong
================================================================
总结,在使用LINQ to DataSet的时候需要注意以下几个方面:
1 在对IEnumeralbe<DataRow>进行数据行的集合操作如Distinct, Except, Union, Intersect,
SequenceEqual时,需要使用System.Data.DatarowComparer.Default作为比较器作为输入参数,以保证对DataRow是进行值比较,而不是引用比较。当然,如果GroupBy或者其他操作的key的类型是DataRow时,也需要使用此比较器,以使我们得到我们期望的行为。
2 SetField可以将字段值设置为null,并且SetField方法将自动将其转换为DBNull.Value.
3 Field可以完成从DBNull.Value到null的转换。也就是说,如果该字段的值是DBNull.Value
时,Field方法将自动将其转为null并返回。这个方法是强类型的,不需要象通过列名或者列索引返回字段值一样将Object类型进行造型成需要的类型(值类型进行拆箱操作),(如果字段的值是DBNull.Value时进行造型还将导致抛出异常)Field扩展方法自动做了这些处理,省去了开发人员手动进行这些处理的麻烦。
4 缺省情况下,数据行的Original版本中是没有值的,试图访问时将导致异常发生。当然,
可以在访问之前使用DataRow.HasVersion来进行判断,以防止异常的发生。也可以通过调用DataRow.AcceptChanges方法来建立Original版本来避免异常的发生。不带LoadOptions参数的CopyToDataTable扩展方法也会为返回的DataTable自动建立DataRow的Original和Current版本.
5 当使用带LoadOptions输入参数的CopyToDataTable扩展方法时,必须为目标DataTable指定主键列,否则,该函数只是将源DataTable追加到目标DataTable的最后面。可能达不到期望更新的结果。
相关文章推荐
- LINQ To DataSet 几个常用示例
- Linq To DataSet 之一(基础查询)
- Linq to DataSet
- LINQ系列:LINQ to DataSet的DataTable操作
- C# LINQ基本用法(4) ---LINQ To DataSet
- Linq To DataSet 之一(基础查询)
- Using LINQ to manipulate data in DataSet/DataTable
- 转载:LINQ to DataSet实现复杂数据查询
- LINQ to DataSet/DataTable
- 再谈谈LINQ TO DataSet
- LINQ to DataSet查询详解
- LINQ TO DataSet Overview(转载)
- Linq to DataSet的Distinct用法
- (转)Rich Query for DataSet- An Introduction to LINQ to DataSet
- LINQ to DataSet实现复杂数据查询
- LINQ to DataSet 【转载】
- LINQ系列:LINQ to DataSet的DataTable操作
- 最近写的各种Linq实例,to xml,to dataset,to object
- Linq to DataSet 学习笔记一
- LINQ to DataSet(弱类型)