程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> LINQ To DataSet

LINQ To DataSet

編輯:關於.NET

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)

從定義中就可 以看出這三類主要是提供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<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
{
  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<DataRow> dt)
  {
     Console.WriteLine ("=============================================================== =");
    try
    {
      foreach (DataRow dataRow in dt.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));
      }
    }
    catch (Exception e)
    {
       Console.WriteLine("Exception:" + e.Message);
     }
    Console.WriteLine ("=============================================================== =");
  }
  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<string>("Name") == "PiPi Zhu"
     select s).Single<DataRow>().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<int>("Id") == 13
     select s).Single<DataRow>().SetField<string> ("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<DataRow> 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的最後面。可能達不到期望更新的結果 。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved