SqlDataReader generates dynamic Lambda expressions and dynamically generates lambda expressions
The previous flat uses a dynamic lambda expression to convert a able to an object, which is much faster than directly using reflection. The delegation is dynamically generated during the first line conversion.
The subsequent conversions all call the delegate directly, saving the performance loss caused by multiple reflections.
Today, SQL Server processes the stream object SqlDataReader returned by SQL Server, and dynamically generates Lambda expressions to convert objects.
Previous Version of code
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 to generate an object // </summary> /// <typeparam name = "T"> </typeparam> // <param name = "d AtaTable "> </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", "Expression Tree cannot be generated when the current object is 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> /// generate the expression /// </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 ", "The current object is null and cannot be converted to an object"); ParameterExpression parameter = E Xpression. 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. mem BerInit (Expression. new (typeof (T), binds. toArray (); return Expression. lambda <Func <DataRow, T> (init, parameter ). compile ();} # endregion // <summary> // generate a lambda expression // </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", "the current object is invalid"); 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 ();}}}
Added the SqlDataReader extension method based on the previous article.
The following code calls
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; } }}
Currently, only objects returned by SQL Server can be processed. In other databases, the extension method of DbDataReader is intended to be added. However, an error occurs when a lambda expression is dynamically generated.
The solution is recorded.