C#中DataTable 转实体实例详解

2019-12-30 17:12:24于海丽

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

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


using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo1
{
  class Program
  {
    static void Main(string[] args)
    {
      DataTable dt = Query();
      List<Usr> usrs = new List<Usr>(dt.Rows.Count);
      //硬编码,效率比较高,但灵活性不够,如果实体改变了,都需要修改代码
      foreach (DataRow dr in dt.Rows)
      {
        Usr usr = new Usr { ID = dr.Field<Int32?>("ID"), Name = dr.Field<String>("Name") };
        usrs.Add(usr);
      }
      usrs.Clear();
    }
    /// <summary>
    /// 查询数据
    /// </summary>
    /// <returns></returns>
    private static DataTable Query()
    {
      DataTable dt = new DataTable();
      dt.Columns.Add("ID", typeof(Int32));
      dt.Columns.Add("Name", typeof(String));
      for (int i = 0; i < 1000000; i++)
      {
        dt.Rows.Add(new Object[] { i, Guid.NewGuid().ToString() });
      }
      return dt;
    }
  }
  class Usr
  {
    public Int32? ID { get; set; }
    public String Name { get; set; }
  }
}

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

程序如下:


static class EntityConvert
  {
    /// <summary>
    /// DataTable转为List<T>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static List<T> ToList<T>(this DataTable dt) where T : class, new()
    {
      List<T> colletion = new List<T>();
      PropertyInfo[] pInfos = typeof(T).GetProperties();
      foreach (DataRow dr in dt.Rows)
      {
        T t = new T();
        foreach (PropertyInfo pInfo in pInfos)
        {
          if (!pInfo.CanWrite) continue;
          pInfo.SetValue(t, dr[pInfo.Name]);
        }
        colletion.Add(t);
      }
      return colletion;
    }
  }

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

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


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

代码如下:


static void Main(string[] args)
    {
      DataTable dt = Query();
      Func<DataRow, Usr> func = dr => new Usr { ID = dr.Field<Int32?>("ID"), Name = dr.Field<String>("Name") };
      List<Usr> usrs = new List<Usr>(dt.Rows.Count);
      Stopwatch sw = Stopwatch.StartNew();
      foreach (DataRow dr in dt.Rows)
      {
        Usr usr = func(dr);
        usrs.Add(usr);
      }
      sw.Stop();
      Console.WriteLine(sw.ElapsedMilliseconds);
      usrs.Clear();
      Console.ReadKey();
    }