欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SqlDataReader生成动态Lambda表达式

程序员文章站 2023-11-12 17:54:10
使用动态lambda表达式来将datatable转换成实体,比直接用反射快了不少。主要是首行转换的时候动态生成了委托。 后面的转换都是直接调用委托,省去了多次用反射带来的...

使用动态lambda表达式来将datatable转换成实体,比直接用反射快了不少。主要是首行转换的时候动态生成了委托。

后面的转换都是直接调用委托,省去了多次用反射带来的性能损失。

今天在对sqlserver返回的流对象 sqldatareader 进行处理,也采用动态生成lambda表达式的方式转换实体。

先上一版代码

using system;
using system.collections.generic;
using system.data;
using system.data.common;
using system.data.sqlclient;
using system.linq;
using system.linq.expressions;
using system.reflection;
using system.text;
using system.threading.tasks;
namespace demo1
{
 public static class entityconverter
 {
  #region
  /// <summary>
  /// datatable生成实体
  /// </summary>
  /// <typeparam name="t"></typeparam>
  /// <param name="datatable"></param>
  /// <returns></returns>
  public static list<t> tolist<t>(this datatable datatable) where t : class, new()
  {
   if (datatable == null || datatable.rows.count <= 0) throw new argumentnullexception("datatable", "当前对象为null无法生成表达式树");
   func<datarow, t> func = datatable.rows[0].toexpression<t>();
   list<t> collection = new list<t>(datatable.rows.count);
   foreach (datarow dr in datatable.rows)
   {
    collection.add(func(dr));
   }
   return collection;
  }
  /// <summary>
  /// 生成表达式
  /// </summary>
  /// <typeparam name="t"></typeparam>
  /// <param name="datarow"></param>
  /// <returns></returns>
  public static func<datarow, t> toexpression<t>(this datarow datarow) where t : class, new()
  {
   if (datarow == null) throw new argumentnullexception("datarow", "当前对象为null 无法转换成实体");
   parameterexpression parameter = expression.parameter(typeof(datarow), "dr");
   list<memberbinding> binds = new list<memberbinding>();
   for (int i = 0; i < datarow.itemarray.length; i++)
   {
    string colname = datarow.table.columns[i].columnname;
    propertyinfo pinfo = typeof(t).getproperty(colname);
    if (pinfo == null || !pinfo.canwrite) continue;
    methodinfo minfo = typeof(datarowextensions).getmethod("field", new type[] { typeof(datarow), typeof(string) }).makegenericmethod(pinfo.propertytype);
    methodcallexpression call = expression.call(minfo, parameter, expression.constant(colname, typeof(string)));
    memberassignment bind = expression.bind(pinfo, call);
    binds.add(bind);
   }
   memberinitexpression init = expression.memberinit(expression.new(typeof(t)), binds.toarray());
   return expression.lambda<func<datarow, t>>(init, parameter).compile();
  }
  #endregion
  /// <summary>
  /// 生成lambda表达式
  /// </summary>
  /// <typeparam name="t"></typeparam>
  /// <param name="reader"></param>
  /// <returns></returns>
  public static func<sqldatareader, t> toexpression<t>(this sqldatareader reader) where t : class, new()
  {
   if (reader == null || reader.isclosed || !reader.hasrows) throw new argumentexception("reader", "当前对象无效");
   parameterexpression parameter = expression.parameter(typeof(sqldatareader), "reader");
   list<memberbinding> binds = new list<memberbinding>();
   for (int i = 0; i < reader.fieldcount; i++)
   {
    string colname = reader.getname(i);
    propertyinfo pinfo = typeof(t).getproperty(colname);
    if (pinfo == null || !pinfo.canwrite) continue;
    methodinfo minfo = reader.gettype().getmethod("getfieldvalue").makegenericmethod(pinfo.propertytype);
    methodcallexpression call = expression.call(parameter, minfo, expression.constant(i));
    memberassignment bind = expression.bind(pinfo, call);
    binds.add(bind);
   }
   memberinitexpression init = expression.memberinit(expression.new(typeof(t)), binds.toarray());
   return expression.lambda<func<sqldatareader, t>>(init, parameter).compile();
  }
 }
}

在上一篇的基础上增加了 sqldatareader 的扩展方法

以下代码是调用

using system;
using system.collections.generic;
using system.data;
using system.data.common;
using system.data.sqlclient;
using system.diagnostics;
using system.linq;
using system.reflection;
using system.text;
using system.threading.tasks;
namespace demo1
{
 class program
 {
  static void main(string[] args)
  {
   string constring = "data source=.; initial catalog=master; integrated security=true;";
   func<sqldatareader, usr> func = null;
   list<usr> usrs = new list<usr>();
   using (sqldatareader reader = getreader(constring, "select object_id 'id',name 'name' from sys.objects", commandtype.text, null))
   {
    while (reader.read())
    {
     if (func == null)
     {
      func = reader.toexpression<usr>();
     }
     usr usr = func(reader);
     usrs.add(usr);
    }
   }
   usrs.clear();
   console.readkey();
  }
  public static sqldatareader getreader(string constring, string sql, commandtype type, params sqlparameter[] pms)
  {
   sqlconnection conn = new sqlconnection(constring);
   sqlcommand cmd = new sqlcommand(sql, conn);
   cmd.commandtype = type;
   if (pms != null && pms.count() > 0)
   {
    cmd.parameters.addrange(pms);
   }
   conn.open();
   return cmd.executereader(commandbehavior.closeconnection);
  }
 }
 class usr
 {
  public int32 id { get; set; }
  public string name { get; set; }
 }
}

目前只能处理sqlserver返回的对象,处理其它数据库本来是想增加 dbdatareader 的扩展方法,但发现动态生成lambda表达式的地方出错,所以先将现在的

方案记录下来。