DataSet Linq 注释笔记用法

LINQ实现

自己实现的功能:

var query1 = from e2 in dtT.AsEnumerable()

                                          select e2.Field<string >("RAW_PN");

 

                             var query = from e1 in dtF.AsEnumerable()

                                        where !(query1).Contains(e1.Field<string >("RAW_PN"))

LINQ to DataSet主要是提供对离线数据的支持,只有在填充DataSet之后, 我们才能使用LINQ to DataSet来查询数据。其功能主要是通过 System.Data.DataRowExtions和System.Data.DataTableExtensions两个静态类 中的扩展方法来公开的。LINQ to DataSet是LINQ to ADO.Net中的一部分,但这 部分所占比重非常小,内容也比较少。下面就让我们首先来看看 DataTableExtensions中的扩展方法:

public static EnumerableRowCollection AsEnumerable(this DataTable source)

------------------------------------------------------------

public static DataView AsDataView(this DataTable table)

public static DataView AsDataView(this EnumerableRowCollection source) where T : DataRow

-------------------------------------------------------------

public static DataTable CopyToDataTable(this IEnumerable source) where T : DataRow

public static void CopyToDataTable(this IEnumerable source,DataTable table,LoadOption options) where T : DataRow

public static void CopyToDataTable(this IEnumerable source,DataTable table,LoadOption options,FillErrorEventHandler errorHandler)

从定义中就可 以看出这三类主要是提供DataTable、DataView和IEnumerable三者之间的转换。 大家都知道LINQ to Object查询主要是对IEnumerable序列进行的操作,这样就 使得DataTable、DataView和LINQ之间建立了一个转换桥梁。

因此,在我 们需要将DataTable应用于LINQ to DataSet查询是要先调用AsEnumerable完成 DataTable到LINQ的转换。如果我们需要将LINQ to DataSet的查询的结果进行数 据绑定时我们需要调用AsDataView的泛型版来完成LINQ到DataView的转换。当然 我们也可以使用CopyToDataTable来进行LINQ到DataTable的转换。

注意 :如果在我们完成了DataTable到LINQ(IEnumerable)的转换之后(也就是调用 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(this DataRow row,DataColumn column)

public static T Field(this DataRow row,int columnIndex)

public static T Field(this DataRow row,string columnName)

public static T Field (this DataRow row,DataColumn column,DataRowVersion version)

public static T Field(this DataRow row,int columnIndex,DataRowVersion version)

public static T Field(this DataRow row,string columnName,DataRowVersion version)

public static void SetField(this DataRow row,DataColumn column,T value)

public static void SetField(this DataRow row,int columnIndex, T value)

public static void SetField(this DataRow row,string columnName,T value)

其中,row: 是我们要使用的数据行对象实例

column: 指定要返回(设 置)其值的列

columnIndex: 指定要返回(设置)其值的列的索引

columnName: 指定要返回(设置)其值的列名

value: 要设置的新 值,如果是null,将自动转换为DBNull.Value

version: 要获取的数据行 的版本

下面,我们就来看看一个使用LINQ to DataSet的实例,这个例子 主要描述了一下上面扩展方法的用法,同时给出了部分注意的事项:

public static class LINQToDataSet

{

  public class Student

  {

    public int Id;

     public string Name;

  }

  public static DataTable GetDataTable(Student[] students)

  {

    DataTable table = new DataTable();

    table.Columns.Add ("Id", typeof(Int32));

    table.Columns.Add ("Name", typeof(string));

    foreach (Student student in students)

    {

      table.Rows.Add (student.Id, student.Name);

    }

    return (table);

  }

  public static void PrintStudentTable (DataTable dt)

  {

    PrintStudentTable (dt.AsEnumerable());

  }

  public static void PrintStudentTable(IEnumerable dt)

  {

     Console.WriteLine ("=============================================================== =");

    try

    {

      foreach (DataRow dataRow in dt.AsEnumerable())

      {

         Console.WriteLine("Student Id = {0} :original {1}:current {2}",

dataRow.Field ("Id"),

dataRow.Field("Name", DataRowVersion.Original),

dataRow.Field ("Name", DataRowVersion.Current));

      }

    }

    catch (Exception e)

    {

       Console.WriteLine("Exception:" + e.Message);

     }

    Console.WriteLine ("=============================================================== =");

  }


  这个例子的步骤:

    1, 建立一个originalTable,直接输出,因为没有DataRowVersion.Original 等值,所以抛出异常,导致.

2,通过newTable = orginalTable.AsEnumrable().CopyToDataTable 生成一个新DataTable.然后显示.这样,newTable再调用DataRowVersion.Original  方法时没有问题.

     3,通过setField方法更新值,可以明显看到 Original 和Current值已经发生变化.说明DataTable会纪录变更发生过程.

4,通过setField设置为null都可以,再通过Field显示为空,而不会造成异常.Field 泛型的好处!

5,调用originalTable.AcceptChanges()完成表格可变更,否则异常.,然后newTable.copyToDataTable(Original,LoadOptions.OverwriteChanges)只会简单添加到后面.

   6,通过original.AsEnumable().Distinct()方法,因为不带比较器参数,会得不到想要的结果.

   7,增加比较器original.AsEnumable().Distinct(DataRowComparer.Defalut) 去掉两列值都不同的情况. 因为此时时值比较.

     8,回到copy的主题,如果copy之前设置originalTable的主键. 那么我们将得到完全不重复的值. 如上,copy时不同值会保留.有逐渐就不会.

  注意.originalTable之前已经设置AcceptChanges. 所以之后我们只需要originalTable.PrimaryKey = new DataColumn[] { originalTable.Columns ["Id"] };

    之后,newTable.asEnumable().copyToTable(originalTable,LoadOptions.OverwriteChanges) 就可以完成保留唯一键记录的信息

public static void Test()

  {

    Student[] students = { new Student { Id = 1, Name = "Lazy Bee" },

                new Student { Id = 7, Name = "Flying Wind" },

                 new Student { Id = 13, Name = "PiPi Zhu" },

                new Student { Id = 72, Name = "Chong Chong" }};

    DataTable originalTable = GetDataTable(students);

    //我们试图访问DataTable中数据行的 Orginal版本,由于此时还没有建立原始版本,

    //所以将导致异常

    Console.WriteLine("We try to get access to original version, so we will get the exception.:");

     PrintStudentTable(originalTable);

    //我们使用 CopyToDataTable来建立DataTable中数据行的Orginal版本

     Console.WriteLine("We will use CopyToDataTable to build original version.");

    DataTable newTable = originalTable.AsEnumerable().CopyToDataTable();

     PrintStudentTable(newTable);

    //使用SetField来更新---www.bianceng.cn

     Console.WriteLine("After call SetField to change name.");

    (from s in newTable.AsEnumerable()

      where s.Field("Name") == "PiPi Zhu"

     select s).Single().SetField ("Name", "George Oscar Bluth");

     PrintStudentTable(newTable);

    //使用SetField来设置null

    Console.WriteLine("After call SetField to change name to null.");

    (from s in newTable.AsEnumerable()

     where s.Field("Id") == 13

     select s).Single().SetField ("Name", null);

    PrintStudentTable(newTable);

    //使用CopyToDataTable来合并,由于我们没有指定表的主键,

    //所以只会简单的追加在目标数据表的最后

     Console.WriteLine("After call CopyToDataTable.We will not get our expected result because we have not set primary key.");

     //首先,我们调用AcceptChanges来建立Original版本,否则,避免显示时 抛出异常

    originalTable.AcceptChanges();

    newTable.AsEnumerable().CopyToDataTable(originalTable, LoadOption.OverwriteChanges);

    PrintStudentTable (originalTable);

    //我们使用Distinct来去掉刚才重复的记录, 由于此时我们没有使用DatarowComparer.Default

    //所以我们将 得不到我们想要的结果

    Console.WriteLine("After call Distinct.We will not get our expected result because we have not used DatarowComparer.Default comparer.");

     IEnumerable distinctTable=originalTable.AsEnumerable ().Distinct();

    PrintStudentTable(distinctTable);

     //我们使用Distinct来去掉刚才重复的记录,使用 DatarowComparer.Default比较器

    //所以我们将得到我们想要的 结果

    Console.WriteLine("After call Distinct.this is what we want.");

    distinctTable=originalTable.AsEnumerable().Distinct (DataRowComparer.Default);

    PrintStudentTable (distinctTable);

    //我们先设置主键,然后再使用 CopyToDataTable来合并

    Console.WriteLine("After call CopyToDataTable.this is what we want.");

     originalTable = GetDataTable(students);

     originalTable.PrimaryKey = new DataColumn[] { originalTable.Columns ["Id"] };

    newTable.AsEnumerable ().CopyToDataTable(originalTable, LoadOption.OverwriteChanges);

    PrintStudentTable(originalTable);

  }

}

例子中有比较详尽的注释,相信大家看应该没有什么问题。

这个例子 的输出结果为:

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进行数据行的集合操作如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的最后面。可能达不到期望更新的结果

来源: <http://www.shangxueba.com/jingyan/100410.html>

posted @ 2015-02-27 18:32  hijushen  阅读(615)  评论(0)    收藏  举报