您的位置:首页 > 其它

LINQ Expressions 动态生成委托——DataReader转换为List方法改进

2009-08-21 15:37 405 查看
在上一篇《DataReader转换为List的一种实现》文章中我构建了一个IDataReader得扩展

publicstaticIEnumerable<T>GetEnumerator<T>(thisIDataReaderreader,Func<IDataRecord,T>generator)


这个扩展时接受一个委托类型的参数实现DataReader转换为对应的实体类,而这个委托所执行的方法便是下图的实现:

publicstaticQuestionNotifyInfoCreateQuestionNotifyInfo(IDataRecordrecord)
{
returnnewQuestionNotifyInfo
{
QID=record.Field<int>("QID"),
Title=record.Field<string>("Title"),
AnswerID=record.Field<int>("AnswerID"),
UserID=record.Field<int>("UserID"),
UserName=record.Field<string>("UserName"),
Content=record.Field<string>("Content"),
DateAdded=record.Field<DateTime>("DateAdded"),
NotifyType=record.Field<int>("NotifyType")
};
}



如果项目中想要使用上一篇《DataReader转换为List的一种实现》文章中方案的话,每一个实体类都必须实现一个类似上图中的转换实体方法,虽然我们可以使用代码生成的方式

为每个类实现上诉方法,但不知为何,总是感觉这样的做法还是太机械,而且代码也太丑陋,为此必须寻找一种更好的方法。

观察所有实体类的转换方法,可以看出这些方法有类似的地方,可以抽象为如下的“模板”:

r=>newT

{

Property1=r.Field<Type[Property1]>("Property1"),

Property2=r.Field<Type[Property2]>("Property2"),



}

能不能使用System.Linq.ExpressionsAPI中的方法动态生成这些方法呢?答案是肯定

结合我这里的实际情况实现的代码如下:

publicstaticFunc<IDataRecord,T>DynamicCreateEntity<T>()
{
//Compilesadelegateoftheform(IDataRecordr)=>newT{Prop1=r.Field<Prop1Type>("Prop1"),...}
ParameterExpressionr=Expression.Parameter(typeof(IDataRecord),"r");

//Createpropertybindingsforallwritableproperties
List<MemberBinding>bindings=newList<MemberBinding>();

foreach(PropertyInfopropertyin(typeof(T).GetProperties()))
{
//Createexpressionrepresentingr.Field<property.PropertyType>(property.Name)
MethodCallExpressionpropertyValue=Expression.Call(
typeof(DatabaseExtend).GetMethod("Field").MakeGenericMethod(property.PropertyType),
r,Expression.Constant(property.Name));

//Assignthepropertyvaluetopropertythroughamemberbinding
MemberBindingbinding=Expression.Bind(property,propertyValue);
bindings.Add(binding);
}
//Createtheinitializer,whichinstantiatesaninstanceofTandsetspropertyvalues

//usingthememberbindingswejustcreated
Expressioninitializer=Expression.MemberInit(Expression.New(typeof(T)),bindings);

//Createthelambdaexpression,whichrepresentsthecompletedelegate(r=>initializer)
Expression<Func<IDataRecord,T>>lambda=Expression.Lambda<Func<IDataRecord,T>>(
initializer,r);

returnlambda.Compile();

}




有了上面的方法之后,现在我们必要为每个实体类都增加一个装换的方法了,所有现在我们可以更加简化我们的数据访问层的操作了,继续扩展数据库访问类,添加下面两个扩展方法:

publicstaticIList<T>ExecuteStoredProc<T>(thisDatabasedataBase,stringstoredProcedureName,paramsobject[]parameterValues)
{
IList<T>result=null;
using(IDataReaderdr=dataBase.ExecuteReaderStoredProc(storedProcedureName,parameterValues))
{
result=dr.GetEnumerator(DynamicCreateEntity<T>()).ToList();
}
returnresult;
}
publicstaticIList<T>ExecuteSqlStringc<T>(thisDatabasedataBase,stringformatSqlString,paramsobject[]parameterValues)
{
IList<T>result=null;
using(IDataReaderdr=dataBase.ExecuteReaderSqlString(formatSqlString,parameterValues))
{
result=dr.GetEnumerator(DynamicCreateEntity<T>()).ToList();
}
returnresult;
}


主要参考文章UsingLINQExpressionstoGenerateDynamicMethods
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: