Cet article présente principalement SqlDataReader pour générer des expressions Lambda dynamiques. Les amis qui en ont besoin peuvent s'y référer
L'article précédent utilise des expressions lambda dynamiques pour convertir DataTable en entités. C'est beaucoup plus rapide que d'utiliser directement la réflexion. peu. La raison principale est que la commission est générée dynamiquement lors de la conversion de la première ligne.
Les conversions ultérieures appellent toutes directement le délégué, éliminant ainsi la perte de performances causée par de multiples réflexions.
Aujourd'hui, je traite l'objet flux SqlDataReader renvoyé par SqlServer, et je convertis également des entités en générant dynamiquement des expressions Lambda.
Première version du 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生成实体 /// </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(); } } }
Basé sur l'article précédent, la méthode d'extension de SqlDataReader est ajoutée
Le code suivant s'appelle
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; } } }
Actuellement, nous ne pouvons traiter que les objets renvoyés par sqlserver. Lorsque nous traitons avec d'autres bases de données, nous voulions à l'origine ajouter la méthode d'extension de DbDataReader, mais nous avons trouvé une erreur dans la génération dynamique des expressions lambda, nous avons donc d'abord enregistré le
plan.Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!