zoukankan      html  css  js  c++  java
  • DataTable 转实体

    因为Linq的查询功能很强大,所以从数据库中拿到的数据为了处理方便,我都会转换成实体集合List<T>。

    开始用的是硬编码的方式,好理解,但通用性极低,下面是控件台中的代码:

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Data;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 
     8 namespace Demo1
     9 {
    10     class Program
    11     {
    12         static void Main(string[] args)
    13         {
    14             DataTable dt = Query();
    15             List<Usr> usrs = new List<Usr>(dt.Rows.Count);
    16             //硬编码,效率比较高,但灵活性不够,如果实体改变了,都需要修改代码
    17             foreach (DataRow dr in dt.Rows)
    18             {
    19                 Usr usr = new Usr { ID = dr.Field<Int32?>("ID"), Name = dr.Field<String>("Name") };
    20                 usrs.Add(usr);
    21             }
    22             usrs.Clear();
    23         }
    24 
    25         /// <summary>
    26         /// 查询数据
    27         /// </summary>
    28         /// <returns></returns>
    29         private static DataTable Query()
    30         {
    31             DataTable dt = new DataTable();
    32             dt.Columns.Add("ID", typeof(Int32));
    33             dt.Columns.Add("Name", typeof(String));
    34             for (int i = 0; i < 1000000; i++)
    35             {
    36                 dt.Rows.Add(new Object[] { i, Guid.NewGuid().ToString() });
    37             }
    38             return dt;
    39         }
    40     }
    41     class Usr
    42     {
    43         public Int32? ID { get; set; }
    44         public String Name { get; set; }
    45     }
    46 }
    复制代码

    后来用反射来做这,对实体的属性用反射去赋值,这样就可以对所有的实体通用,且增加属性后不用修改代码。

    程序如下:

    复制代码
     1 static class EntityConvert
     2     {
     3         /// <summary>
     4         /// DataTable转为List<T>
     5         /// </summary>
     6         /// <typeparam name="T"></typeparam>
     7         /// <param name="dt"></param>
     8         /// <returns></returns>
     9         public static List<T> ToList<T>(this DataTable dt) where T : class, new()
    10         {
    11             List<T> colletion = new List<T>();
    12             PropertyInfo[] pInfos = typeof(T).GetProperties();
    13             foreach (DataRow dr in dt.Rows)
    14             {
    15                 T t = new T();
    16                 foreach (PropertyInfo pInfo in pInfos)
    17                 {
    18                     if (!pInfo.CanWrite) continue;
    19                     pInfo.SetValue(t, dr[pInfo.Name]);
    20                 }
    21                 colletion.Add(t);
    22             }
    23             return colletion;
    24         }
    25     }
    复制代码

    增加一个扩展方法,程序更加通用。但效率不怎么样,100万行数据【只有两列】,转换需要2秒

    后来想到用委托去做 委托原型如下 

    1  Func<DataRow, Usr> func = dr => new Usr { ID = dr.Field<Int32?>("ID"), Name = dr.Field<String>("Name") };

    代码如下:

    复制代码
     1 static void Main(string[] args)
     2         {
     3             DataTable dt = Query();
     4             Func<DataRow, Usr> func = dr => new Usr { ID = dr.Field<Int32?>("ID"), Name = dr.Field<String>("Name") };
     5             List<Usr> usrs = new List<Usr>(dt.Rows.Count);
     6             Stopwatch sw = Stopwatch.StartNew();
     7             foreach (DataRow dr in dt.Rows)
     8             {
     9                 Usr usr = func(dr);
    10                 usrs.Add(usr);
    11             }
    12             sw.Stop();
    13             Console.WriteLine(sw.ElapsedMilliseconds);
    14             usrs.Clear();
    15             Console.ReadKey();
    16         }
    复制代码

    速度确实快了很多,我电脑测试了一下,需要 0.4秒。但问题又来了,这个只能用于Usr这个类,得想办法把这个类抽象成泛型T,既有委托的高效,又有

    泛型的通用。

    问题就在动态地产生上面的委托了,经过一下午的折腾终于折腾出来了动态产生委托的方法。主要用到了动态Lambda表达式

    复制代码
    复制代码
     1 public static class EntityConverter
     2     {
     3         /// <summary>
     4         /// DataTable生成实体
     5         /// </summary>
     6         /// <typeparam name="T"></typeparam>
     7         /// <param name="dataTable"></param>
     8         /// <returns></returns>
     9         public static List<T> ToList<T>(this DataTable dataTable) where T : class, new()
    10         {
    11             if (dataTable == null || dataTable.Rows.Count <= 0) throw new ArgumentNullException("dataTable", "当前对象为null无法生成表达式树");
    12             Func<DataRow, T> func = dataTable.Rows[0].ToExpression<T>();
    13             List<T> collection = new List<T>(dataTable.Rows.Count);
    14             foreach (DataRow dr in dataTable.Rows)
    15             {
    16                 collection.Add(func(dr));
    17             }
    18             return collection;
    19         }
    20 
    21         /// <summary>
    22         /// 生成表达式
    23         /// </summary>
    24         /// <typeparam name="T"></typeparam>
    25         /// <param name="dataRow"></param>
    26         /// <returns></returns>
    27         public static Func<DataRow, T> ToExpression<T>(this DataRow dataRow) where T : class, new()
    28         {
    29             if (dataRow == null) throw new ArgumentNullException("dataRow", "当前对象为null 无法转换成实体");
    30             ParameterExpression paramter = Expression.Parameter(typeof(DataRow), "dr");
    31             List<MemberBinding> binds = new List<MemberBinding>();
    32             for (int i = 0; i < dataRow.ItemArray.Length; i++)
    33             {
    34                 String colName = dataRow.Table.Columns[i].ColumnName;
    35                 PropertyInfo pInfo = typeof(T).GetProperty(colName);
    36                 if (pInfo == null) continue;
    37                 MethodInfo mInfo = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(String) }).MakeGenericMethod(pInfo.PropertyType);
    38                 MethodCallExpression call = Expression.Call(mInfo, paramter, Expression.Constant(colName, typeof(String)));
    39                 MemberAssignment bind = Expression.Bind(pInfo, call);
    40                 binds.Add(bind);
    41             }
    42             MemberInitExpression init = Expression.MemberInit(Expression.New(typeof(T)), binds.ToArray());
    43             return Expression.Lambda<Func<DataRow, T>>(init, paramter).Compile();
    44         }
    45     }
    复制代码
    复制代码

    经过测试,用这个方法在同样的条件下转换实体需要 0.47秒。除了第一次用反射生成Lambda表达式外,后续的转换直接用的表达式。

    原文:http://www.cnblogs.com/lclblog/p/6701814.html

  • 相关阅读:
    第三天 moyax
    mkfs.ext3 option
    write file to stroage trigger kernel warning
    download fomat install rootfs script
    custom usb-seriel udev relus for compatible usb-seriel devices using kermit
    Wifi Troughput Test using iperf
    learning uboot switch to standby system using button
    learning uboot support web http function in qca4531 cpu
    learngin uboot design parameter recovery mechanism
    learning uboot auto switch to stanbdy system in qca4531 cpu
  • 原文地址:https://www.cnblogs.com/yanglang/p/6707522.html
Copyright © 2011-2022 走看看