我尝试构建动态LINQ到实体查询构建器,以使用属性名称作为字符串返回过滤器表达式,或者检查类型中所有属性的表达式。如果属性是整数,我想检查它是否等于搜索值,否则我想看看属性的字符串值是否包含搜索值。
构建器有两个方法:一个在将属性名称作为字符串和搜索值传递时返回lambda表达式,另一个根据搜索值检查该类型中的所有属性。
对于搜索单个属性,我有以下内容:
public static Expression<Func<TEntity, bool>> GetFilter<TEntity>(string data, string propertyName)
{
var parameter = Expression.Parameter(typeof(TEntity));
Type t = typeof(TEntity).GetProperty(propertyName).PropertyType;
var property = Expression.PropertyOrField(parameter, propertyName);
ConstantExpression constant;
Expression predicate;
if (t == typeof(int))
{
int temp;
bool check = int.TryParse(data, out temp);
if (!check)
{
return ((TEntity x) => false);
}
constant = Expression.Constant(temp);
predicate = Expression.Call(property, "Equals", null, constant);
}
else
{
constant = Expression.Constant(data);
var toString = Expression.Call(property, "ToString", null);
predicate = Expression.Call(toString, "Contains", null, constant);
}
return Expression.Lambda<Func<TEntity, bool>>(predicate, parameter);
}
这完美无缺。但是,当尝试使用所有属性执行此操作时,我收到NotSupportedException,指出ToString()无法转换为有效的SQL查询。
要设置表达式,我有一个名为exp的临时表达式,设置它的代码完全相同。然后我连接了#39;通过调用Expression.Or()
来表达式 public static Expression<Func<TEntity, bool>> GetFilterForAll<TEntity>(string data)
{
Type t = typeof(TEntity);
var parameter = Expression.Parameter(t);
var properties = from p in t.GetProperties()
where p.CanRead && !p.GetGetMethod().IsVirtual && p.Name.ToLower() != "id"
select Expression.PropertyOrField(parameter, p.Name);
Expression predicate = null;
foreach (var prop in properties)
{
ConstantExpression constant;
Expression exp;
if (prop.Type == typeof(int))
{
int temp;
bool check = int.TryParse(data, out temp);
if (!check)
{
continue;
}
constant = Expression.Constant(temp);
exp = Expression.Call(prop, "Equals", null, constant);
}
else
{
constant = Expression.Constant(data);
var toString = Expression.Call(prop, "ToString", null);
exp = Expression.Call(toString, "Contains", null, constant);
}
if (predicate == null)
{
predicate = exp;
}
else
{
predicate = Expression.Or(predicate, exp);
}
}
if (predicate == null) return null;
return Expression.Lambda<Func<TEntity, bool>>(predicate, parameter);
}
我知道我在某个地方出错了,特别是因为今天已经学到了所有这些,我怀疑我是如何做到的,或者是&#39;表达式。
答案 0 :(得分:1)
我在没有 等于 的情况下执行此操作,因为不在范围内我将需要创建一些attr或flag来设置将过滤的道具 完全 或 可能 ,我只是进入导航的1级深度,所以也许这可以帮助您理解:
private static readonly MethodInfo ToStringMethod = typeof(object).GetMethod("ToString");
private static readonly MethodInfo StringContainsMethod = typeof(string).GetMethod("Contains");
public static Expression<Func<T, bool>> BuildFilterPredicate<T>(string q)
{
var query = Expression.Constant(q);
var type = typeof(T);
var lambdaParam = Expression.Parameter(type);
var predicates = type.GetProperties().SelectMany(p => PredicateContainsBuilder(lambdaParam, p, query)).ToList();
Expression body = predicates[0];
body = predicates.Skip(1).Aggregate(body, Expression.OrElse);
return Expression.Lambda<Func<T, bool>>(body, lambdaParam);
}
private static IEnumerable<MethodCallExpression> PredicateContainsBuilder(Expression lambdaParam, PropertyInfo prop, Expression query)
{
if (prop.PropertyType.IsClass)
return new List<MethodCallExpression> { Expression.Call(Expression.Call(Expression.Property(lambdaParam, prop), ToStringMethod), StringContainsMethod, query) };
var properties = prop.PropertyType.GetProperties();
return properties.Select(p => Expression.Call(Expression.Call(Expression.Property(lambdaParam, p), ToStringMethod), StringContainsMethod, query)).ToList();
}
尝试使用OrElse
代替Or