Linq To Sql进阶系列(六)用object的动态查询与保存log篇
[2] Linq To Sql进阶系列(六)用object的动态查询与保存log篇
[3] Linq To Sql进阶系列(六)用object的动态查询与保存log篇
系列文章导航:
Linq To Sql进阶系列(四)User Define Function篇
Linq To Sql进阶系列(五)Store Procedure篇
Linq To Sql进阶系列(六)用object的动态查询与保存log篇
Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别
2,原理
Linq To Sql支持用户动态生成lambda表达式。本文中所实现的方法,正是反射加lambda动态表达式。我们先来看如何动态生成lambda表达式。在Linq 中,lambda表达式会首先转化为Expression Tree,本文并不详解Expression Tree。Expression Tree是lambda表达式从code的形式转化为data的结果,是一种更高效的在内存中的数据结构。比如:
Func<int,int> f = x => x + 1; // Code
Expression<Func<int,int>> e = x => x + 1; // Data
第二个,其实也就是第一个转化后的形式。那好了,有了这个前提,我们就可以动态构造这个Expression Tree了。
// 先构造了一个ParameterExpression对象,这里的c,就是Lambda表达中的参数。(c=>)
ParameterExpression param = Expression.Parameter(typeof(TEntity), "c");
//构造表达式的右边,值的一边
Expression right = Expression.Constant(p.GetValue(obj, null));
//构造表达式的左边,property一端。
Expression left = Expression.Property(param, p.Name);
//生成筛选表达式。即c.CustomerID == "Tom"
Expression filter = Expression.Equal(left, right);
//生成完整的Lambda表达式。
Expression<Func<TEntity, bool>> pred = Expression.Lambda<Func<TEntity, bool>>(filter, param);
//在这里,我们使用的是and条件。
query = query.Where(pred);
3,反射在本方法中的作用
因为我们采用了模板,也就是说,我们并不知道传进来的对象会有那些property,那反射在这里就提供一个很好的方法。我们可以通过反射去遍历每一个property,只有判断出该property的值不为null时,才将其视为条件。该函数完整的代码如下:
{
//获得所有property的信息
PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public |
BindingFlags.Instance);
//构造初始的query
IQueryable<TEntity> query = this.GetTable<TEntity>().AsQueryable<TEntity>();
//遍历每个property
foreach (PropertyInfo p in properties)
{
if (p != null)
{
Type t = p.PropertyType;
//加入object,Binary,和XDocument, 支持sql_variant,imager 和xml等的影射。
if (t.IsValueType || t == typeof(string) || t == typeof(System.Byte[])
|| t == typeof(object) || t == typeof(System.Xml.Linq.XDocument)
|| t == typeof(System.Data.Linq.Binary))
{
//如果不为null才算做条件
if ( p.GetValue(obj, null) != null)
{
ParameterExpression param = Expression.Parameter(typeof(TEntity), "c");
Expression right = Expression.Constant(p.GetValue(obj, null));
Expression left = Expression.Property(param, p.Name);
Expression filter = Expression.Equal(left,right);
Expression<Func<TEntity, bool>> pred = Expression.Lambda<Func
<TEntity, bool>>(filter, param);
query = query.Where(pred);
}
}
}
}
return query;
}