.Net工具类--表达式目录树解析DataReader和DataTable
一、概述
在项目中经常会使用SQL去操作数据库,在读取数据的时候返回结果一般是DataReader和DataSet,其中DataaSet里面可以包含多个DataTable。
读取到数据之后,一般情况下,我们需要把DataReader和DataSet解析成另外的数据实体和数据集合,有人会选择反射、硬编码,这些都是解决方案,
其实还有其他的解决方案,那就是表达式目录树。
二、解析DataReader
这个是生成表达式的方法。
/// <summary> /// SqlDataReader生成表达式 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="reader"></param> /// <returns></returns> public static Func<SqlDataReader, T> ToExpression<T>(this SqlDataReader reader) { 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()); var expr = Expression.Lambda<Func<SqlDataReader, T>>(init, parameter).Compile(); return expr; }
调用,这个方法写的比较简陋,只写了获取单个数据行,有需要其他类型的可以扩展一下。
public static T GetTById(List<SqlParameter> parameters) { try { var model = Activator.CreateInstance<T>(); string sql = GetBasicQuerySql() + " WHERE Id = @Id"; Console.WriteLine(sql); SqlDataReader result = null; SqlConn(sql, (reader) => { result = (SqlDataReader)reader; }, SqlType.GetModel, parameters); if (result.Read()) { Func<SqlDataReader, T> func = result.ToExpression<T>(); model = func(result); } return model; } catch (Exception ex) { throw ex; } }
三、解析DataTable
下面是解析DataTable的,可以直接调用,写的是DataTable的扩展方法,调用方式和ToString一样,就不举例了。
/// <summary> /// DataTable生成实体 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="dataTable"></param> /// <returns></returns> public static List<T> ToList<T>(this DataTable dataTable) { 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) { 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(); }
学无止境,多积累,多实践。