Linq To DataTable

来源:互联网 发布:网络语言暴力毕业论文 编辑:程序博客网 时间:2024/04/30 19:15
1.從查詢中建立 DataTable (LINQ to DataSet)

資料繫結 (Data Binding) 是 DataTable 物件的常見用法。CopyToDataTable 方法會採用查詢的結果並將資料複製到DataTable 中,然後此物件便可用於資料繫結。執行了資料作業之後,新的 DataTable 就會合併回來源DataTable 中。

CopyToDataTable 方法會使用下列程序,從查詢中建立DataTable

  1. CopyToDataTable 方法會從來源資料表 (實作IQueryable<T> 介面的DataTable 物件) 中複製 (Clone)DataTableIEnumerable 來源通常源自於 LINQ to DataSet 運算式或方法查詢。

  2. 複製的 DataTable 結構描述是根據來源資料表中第一個列舉DataRow 物件的資料行所建立,而且複製之資料表的名稱就是來源資料表的名稱並附加上 "query" 一字。

  3. 若為來源資料表中的每個資料列,資料列的內容會複製到新的 DataRow 物件中,然後該物件便插入複製的資料表中。在複製作業中,RowStateRowError 屬性會保留下來。如果來源中的 DataRow 物件來自於不同的資料表,系統就會擲回ArgumentException

  4. 在輸入可查詢資料表中的所有 DataRow 物件都已經複製之後,就會傳回複製的DataTable如果來源序列 (Sequence) 沒有包含任何 DataRow 物件,此方法就會傳回空的DataTable

請注意,呼叫 CopyToDataTable 方法將導致系統執行繫結至來源資料表的查詢。

CopyToDataTable 方法在來源資料表的資料列中遇到 Null 參考或可為 Null 的實值型別 (Value Type) 時,它會將此值取代成Value如此一來,傳回之 DataTable 中的 Null 值都會經過正確處理。

注意:CopyToDataTable 方法會接受可從多個DataTableDataSet 物件傳回資料列的查詢當做輸入。CopyToDataTable 方法會將資料 (但不包含屬性) 從來源DataTableDataSet 物件複製到傳回的DataTable您必須針對傳回的 DataTable 明確設定屬性,例如LocaleTableName

下列範例將在 SalesOrderHeader 資料表中查詢是否有 2001 年 8 月 8 日之後的訂單,然後使用CopyToDataTable 方法,從該查詢中建立DataTable接著,DataTable 便繫結至BindingSource,而它會當做DataGridView 的 Proxy。

C#
VB
複製
// Bind the System.Windows.Forms.DataGridView object// to the System.Windows.Forms.BindingSource object.dataGridView.DataSource = bindingSource;// Fill the DataSet.DataSet ds = new DataSet();ds.Locale = CultureInfo.InvariantCulture;FillDataSet(ds);DataTable orders = ds.Tables["SalesOrderHeader"];// Query the SalesOrderHeader table for orders placed // after August 8, 2001.IEnumerable<DataRow> query =    from order in orders.AsEnumerable()    where order.Field<DateTime>("OrderDate") > new DateTime(2001, 8, 1)    select order;// Create a table from the query.DataTable boundTable = query.CopyToDataTable<DataRow>();// Bind the table to a System.Windows.Forms.BindingSource object, // which acts as a proxy for a System.Windows.Forms.DataGridView object.bindingSource.DataSource = boundTable;
建立自訂 CopyToDataTable<T> 方法

現有的 CopyToDataTable 方法只能在通用參數TDataRow 型別的IEnumerable<T> 來源上運作。 雖然這樣非常有用,但是資料表卻無法從一序列的純量型別、傳回匿名型別的查詢或執行資料表聯結的查詢建立。如需如何實作從一序列的純量型別或匿名型別載入資料表的兩個自訂 CopyToDataTable 方法的範例,請參閱HOW TO:實作通用型別 T 不是 DataRow 的 CopyToDataTable<T>

本節的範例都使用以下自訂型別:

C#
VB
複製
public class Item{    public int Id { get; set; }    public double Price { get; set; }    public string Genre { get; set; }}public class Book : Item{    public string Author { get; set; }}public class Movie : Item{    public string Director { get; set; }}

範例

此範例會執行 SalesOrderHeaderSalesOrderDetail 資料表的聯結,以取得八月的線上訂單資訊並根據此查詢建立資料表。

C#
VB
複製
// Fill the DataSet.DataSet ds = new DataSet();ds.Locale = CultureInfo.InvariantCulture;FillDataSet(ds);DataTable orders = ds.Tables["SalesOrderHeader"];DataTable details = ds.Tables["SalesOrderDetail"];var query =    from order in orders.AsEnumerable()    join detail in details.AsEnumerable()    on order.Field<int>("SalesOrderID") equals        detail.Field<int>("SalesOrderID")    where order.Field<bool>("OnlineOrderFlag") == true    && order.Field<DateTime>("OrderDate").Month == 8    select new    {        SalesOrderID =            order.Field<int>("SalesOrderID"),        SalesOrderDetailID =            detail.Field<int>("SalesOrderDetailID"),        OrderDate =            order.Field<DateTime>("OrderDate"),        ProductID =            detail.Field<int>("ProductID")    };DataTable orderTable = query.CopyToDataTable(); 

範例

下列範例會查詢集合中價格大於 $9.99 的項目,並根據查詢結果建立資料表。

C#
VB
複製
// Create a sequence. Item[] items = new Item[] { new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},   new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},  new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},  new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};// Query for items with price greater than 9.99.var query = from i in items             where i.Price > 9.99             orderby i.Price             select i;// Load the query results into new DataTable.DataTable table = query.CopyToDataTable();

範例

下列範例會查詢集合中價格大於 $9.99 的項目並擲回結果。 所傳回的匿名型別序列就會載入到現有的資料表中。

C#
VB
複製
// Create a sequence. Item[] items = new Item[] { new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},   new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},  new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},  new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};// Create a table with a schema that matches that of the query results.            DataTable table = new DataTable();table.Columns.Add("Price", typeof(int));table.Columns.Add("Genre", typeof(string));var query = from i in items             where i.Price > 9.99             orderby i.Price             select new { i.Price, i.Genre };query.CopyToDataTable(table, LoadOption.PreserveChanges);

範例

下列範例會查詢集合中價格大於 $9.99 的項目並擲回結果。 所傳回的匿名型別序列就會載入到現有的資料表中。 因為 BookMovies 型別是衍生自 Item 型別,所以資料表結構描述會自動展開。

C#
VB
複製
// Create a sequence. Item[] items = new Item[] { new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},   new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},  new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},  new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};// Load into an existing DataTable, expand the schema and// autogenerate a new Id.DataTable table = new DataTable();DataColumn dc = table.Columns.Add("NewId", typeof(int));dc.AutoIncrement = true;table.Columns.Add("ExtraColumn", typeof(string));var query = from i in items             where i.Price > 9.99             orderby i.Price             select new { i.Price, i.Genre };query.CopyToDataTable(table, LoadOption.PreserveChanges);

範例

下列範例會查詢集合中價格大於 $9.99 的項目並傳回結果 Double 序列,這序列會在入到新資料表中。

// Create a sequence. Item[] items = new Item[] { new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"},   new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},  new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},  new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};// load sequence of scalars.IEnumerable<double> query = from i in items             where i.Price > 9.99             orderby i.Price             select i.Price;DataTable table = query.CopyToDataTable();



2.Linq To DataTable

Linq 有很多值得学习的地方,这里我们主要介绍Linq To DataTable,包括介绍DataTable类型等方面。

Linq To DataTable

Linq已经让我们感觉不到Query的难点, 它让我们很容易的实现高难度的Query。 或许剩下的问题,也许是很简单的问题就是如何保存这些Query结果?

 

  1. var_result =DAL.Utility.SelectAll<Customer>(); 
  1. var_filter
  1. from q in _result 
  1. where q.CustomerID.StartsWith("B") 
  1. select new 
  1. q.CustomerID, 
  2. q.ContactName, 
  1. q.CompanyName 
  1. };

_result 是搜索所有Customer的结果,_filter 是 _result 中 CustomerID以“B”开始的{CustomerID , ContactName, CompanyName} 集合,但是这个匿名类型就没办法作为变量 return给另外一个方法调用。

可能把这个{CustomerID , ContactName, CompanyName}集合反射到一个DataTable类型是比较符合一般数据库需求的, 或许说这也是某些旧系统轻松插上Linq翅膀的一种方案。

下面给出Linq To DataTable的方法(某种意义上是一样的):

 

  1. public static System.Data.DataTable LinqToDataTable<T>(IEnumerable<T> data) 
  2. var dt =new System.Data.DataTable(); 
  3. var ps =typeof(T).GetProperties().ToList(); 
  4. ps.ForEach(p => dt.Columns.Add(p.Name, p.PropertyType)); 
  5. foreach (T t in data) 
  1. vardr =dt.NewRow(); 
  2. var vs =from p in ps select p.GetValue(t, null); 
  1. varls =vs.ToList(); 
  2. int i =0
  3. ls.ForEach(c => dr[i++] = c); 
  4. dt.Rows.Add(dr); 
  5. return dt; 
  1. public static System.Data.DataTable ToDataTable<T>(IEnumerable<T> data) 
  2. var dt =new System.Data.DataTable(); 
  1. varps=System.ComponentModel.TypeDescriptor.GetProperties(typeof(T)); 
  2. foreach (System.ComponentModel.PropertyDescriptor dp in ps ) 
  1. dt.Columns.Add(dp.Name, dp.PropertyType); 
  1. foreach (T t in data) 
  1. var dr =dt.NewRow(); 
  2. foreach (System.ComponentModel.PropertyDescriptor dp in ps) 
  3. dr[dp.Name] = dp.GetValue(t); 
  4. dt.Rows.Add(dr); 
  5. return dt; 
  6. }