Funny Linq Part3: Linq To DataTable
这篇文章某些地方还是承接第一篇文章
Linq已经让我们感觉不到Query的难点, 它让我们很容易的实现高难度的Query。 或许剩下的问题, 也许是很简单的问题就是如何保存这些Query结果?
例如:
- var _result = DAL.Utility.SelectAll<Customer>();
- var _filter =
- from q in _result
- where q.CustomerID.StartsWith("B")
- select new
- {
- q.CustomerID,
- q.ContactName,
- q.CompanyName
- };
_result 是搜索所有Customer的结果,_filter 是 _result 中 CustomerID 以“B”开始的{CustomerID , ContactName, CompanyName} 集合,但是这个匿名类型就没办法作为变量 return 给另外一个方法调用。
可能把这个{CustomerID , ContactName, CompanyName} 集合反射到一个DataTable类型是比较符合一般数据库需求的, 或许说这也是某些旧系统轻松插上Linq翅膀的一种方案。
下面给出两个Convert To DataTable 的方法(某种意义上是一样的):
- public static System.Data.DataTable LinqToDataTable<T>(IEnumerable<T> data)
- {
- var dt = new System.Data.DataTable();
- var ps = typeof(T).GetProperties().ToList();
- ps.ForEach(p => dt.Columns.Add(p.Name, p.PropertyType));
- foreach (T t in data)
- {
- var dr = dt.NewRow();
- var vs = from p in ps select p.GetValue(t, null);
- var ls = vs.ToList();
- int i = 0;
- ls.ForEach(c => dr[i++] = c);
- dt.Rows.Add(dr);
- }
- return dt;
- }
- public static System.Data.DataTable ToDataTable<T>(IEnumerable<T> data)
- {
- var dt = new System.Data.DataTable();
- var ps= System.ComponentModel.TypeDescriptor.GetProperties(typeof(T));
- foreach (System.ComponentModel.PropertyDescriptor dp in ps )
- dt.Columns.Add(dp.Name, dp.PropertyType);
- foreach (T t in data)
- {
- var dr = dt.NewRow();
- foreach (System.ComponentModel.PropertyDescriptor dp in ps)
- dr[dp.Name] = dp.GetValue(t);
- dt.Rows.Add(dr);
- }
- return dt;
- }
下面给出一个Testing Project 来测试一下这两个方法:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using DLinq;
- using Toolkits;
- namespace ToolkitsTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- ToDataTableTest();
- }
- private static void ToDataTableTest()
- {
- var _result = DAL.Utility.SelectAll<Customer>();
- var _filter =
- from q in _result
- where q.CustomerID.StartsWith("B")
- select new
- {
- q.CustomerID,
- q.ContactName,
- q.CompanyName
- };
- var dt1= BLReflection.LinqToDataTable(_filter);
- var dt2= BLReflection.ToDataTable(_filter);
- var _str1 = StringExtension.ToString(dt1);
- var _str2 = StringExtension.ToString(dt2);
- Console.WriteLine(_str1);
- Console.WriteLine(_str2);
- Console.Read();
- }
- }
- }
相信看过前两篇文章的人都应该记得StringExtension类了, 这里增加了一个方法ToString (System.Data.DataTable data):
- public static string ToString(System.Data.DataTable data)
- {
- StringBuilder sb = new StringBuilder();
- int colCount = data.Columns.Count;
- foreach (System.Data.DataRow dr in data.Rows)
- {
- for (int i = 0; i < colCount; i++)
- {
- string s = (dr[i] == null ? string.Empty : dr[i].ToString());
- sb.Append(s);
- sb.Append(", ");
- }
- sb.AppendLine();
- }
- return sb.ToString();
- }
最后,测试结果应该是这样的(两个方法转换的结果都一样):
BERGS, Christina Berglund, Berglunds snabbk?p,
BLAUS, Hanna Moos, Blauer See Delikatessen,
BLONP, Frédérique Citeaux, Blondesddsl père et fils,
BOLID, Martín Sommer, Bólido Comidas preparadas,
BONAP, Laurence Lebihan, Bon app',
BOTTM, Elizabeth Lincoln, Bottom-Dollar Markets,
BSBEV, Victoria Ashworth, B's Beverages,
BERGS, Christina Berglund, Berglunds snabbk?p,
BLAUS, Hanna Moos, Blauer See Delikatessen,
BLONP, Frédérique Citeaux, Blondesddsl père et fils,
BOLID, Martín Sommer, Bólido Comidas preparadas,
BONAP, Laurence Lebihan, Bon app',
BOTTM, Elizabeth Lincoln, Bottom-Dollar Markets,
BSBEV, Victoria Ashworth, B's Beverages,
2009年5月16日更新:
另一种方法:
public static DataTable ToDataTable <T>(IEnumerable <T> varlist)
{
DataTable dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null) return dtReturn;
foreach (T rec in varlist)
{
if (oProps == null)
{
oProps = ((Type)rec.GetType()).GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition()
== typeof(Nullable <>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
(rec, null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}