在我的应用程序中,我有一些实现一个通用接口的clasess,我们称之为IValidator。 实现此类接口的每个类都返回PredicateGroup对象。所以出于测试目的,我 决定从数据库的特定视图中获取所有数据,然后在返回的集合上获取(IEnumerable) 通过linq进行快速过滤(不需要使用不同的谓词对数据库进行多次调用)。
dapper是否支持从IPredicate / PredicateGroup到Func<>的转换还是有另一个更快/更好的解决方案?
这里有一个小小的介绍我想要实现的目标:
IEnumerable<Products> products = null;
using (var cn = new SqlConnection("connectionstring"))
{
//Get all elemnts from database(using only one call)
products = cn.GetList<Products>(Predicates.Field<Products>(f => f.Discontinued, Operator.Eq, true));
}
// class which implement IValidator and returns predicate group
List<IPredicate> computerPredicates = new List<IPredicate>
{
Predicates.Field<Products>(f => f.ProductName, Operator.Eq, "Computer"),
Predicates.Field<Products>(f => f.Price, Operator.Eq, 1200)
};
var computerPredicatesGroup = new PredicateGroup {Predicates = computerPredicates };
// class which implement IValidator and returns predicate group
List<IPredicate> phonePredicates = new List<IPredicate>
{
Predicates.Field<Products>(f => f.ProductName, Operator.Eq, "Phone"),
Predicates.Field<Products>(f => f.Price, Operator.Eq, 400)
};
var phonePredicatesGroup = new PredicateGroup { Predicates = phonePredicates };
var computers = products.Where( /* computerPredicates */); //??
var phones = products.Where( /* phonePredicatesGroup */); //??
答案 0 :(得分:0)
我没有找到任何解决方案所以我决定编写自己的解析器。
如何使用它的示例:
测试模型:
class TestCarModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Model { get; set; }
public string Type { get; set; }
public float Cost { get; set; }
}
private List<TestCarModel> PrepareTestData()
{
return new List<TestCarModel>()
{
new TestCarModel(){ Id = 1, Name = "Fiat", Model = "500", Type = "Kompakt", Cost = 20000 },
new TestCarModel(){ Id = 2, Name = "Fiat", Model = "Bravo", Type = "Kompakt", Cost = 30000 },
new TestCarModel(){ Id = 3, Name = "Opel", Model = "Astra", Type = "Sedan", Cost = 20000 },
new TestCarModel(){ Id = 4, Name = "Honda", Model = "Civic", Type = "Hatchback", Cost = 15000 },
new TestCarModel(){ Id = 5, Name = "Audi", Model = "A4", Type = "Sedan", Cost = 40000 },
};
}
示例1:
var groupPredicate = new PredicateGroup
{
Operator = GroupOperator.Or,
Predicates = new List<IPredicate>()
};
var predicateGroup1 = new PredicateGroup
{
Operator = GroupOperator.Or,
Predicates = new List<IPredicate>()
{
Predicates.Field<TestCarModel>(f => f.Model, Operator.Eq, "500"),
Predicates.Field<TestCarModel>(f => f.Model, Operator.Eq, "Bravo")
}
};
var predicateGroup2 = new PredicateGroup
{
Operator = GroupOperator.Or,
Predicates = new List<IPredicate>()
{
Predicates.Field<TestCarModel>(f => f.Name, Operator.Eq, "Opel"),
Predicates.Field<TestCarModel>(f => f.Type, Operator.Eq, "Hatchback"),
}
};
groupPredicate.Predicates.Add(Predicates.Field<TestCarModel>(f => f.Cost, Operator.Gt, 35000));
groupPredicate.Predicates.Add(predicateGroup1);
groupPredicate.Predicates.Add(predicateGroup2);
var testdata = PrepareTestData();
var expression = PredicateParser<TestCarModel>.Parse(groupPredicate).Compile();
var result = testdata.Where(expression);
示例2:
var predicates = new List<IPredicate>
{
Predicates.Field<TestCarModel>(f => f.Type, Operator.Eq, "Sedan"),
Predicates.Field<TestCarModel>(f => f.Type, Operator.Eq, "Hatchback"),
};
var testdata = PrepareTestData();
var expression = PredicateParser<TestCarModel>.ParseOr(predicates).Compile();
var result = testdata.Where(expression);
<强>代码:强>
PredicateParser
public static class PredicateParser<T>
{
public static Expression<Func<T, bool>> Parse(PredicateGroup predicateGroup)
{
var compositeIterator = new CompositeIterator<T>();
var result = compositeIterator.Prepare(predicateGroup);
return result;
}
public static Expression<Func<T, bool>> ParseAnd(IList<IPredicate> fieldPredicates)
{
Expression<Func<T, bool>> finalQuery = t => true;
foreach (var predicate in fieldPredicates)
{
finalQuery = finalQuery.And(Parse(predicate));
}
return finalQuery;
}
public static Expression<Func<T, bool>> ParseOr(IList<IPredicate> fieldPredicates)
{
Expression<Func<T, bool>> finalQuery = t => false;
foreach (var predicate in fieldPredicates)
{
finalQuery = finalQuery.Or(Parse(predicate));
}
return finalQuery;
}
public static Expression<Func<T, bool>> Parse(IPredicate predicate)
{
IFieldPredicate fieldPredicate = (IFieldPredicate)predicate;
ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, fieldPredicate.PropertyName);
UnaryExpression propertyValue = Expression.Convert(Expression.Constant(fieldPredicate.Value), memberExpression.Type);
var operatorMatrix = new Dictionary<KeyValuePair<Operator, bool>, Func<Expression>>
{
{ new KeyValuePair<Operator, bool>(Operator.Like, false), () => LikeExpression.Like(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Eq, false), () => Expression.Equal(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Gt, false), () => Expression.GreaterThan(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Ge, false), () => Expression.GreaterThanOrEqual(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Lt, false), () => Expression.LessThan(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Le, false), () => Expression.LessThanOrEqual(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Like, true), () => LikeExpression.NotLike(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Eq, true), () => Expression.NotEqual(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Gt, true), () => Expression.LessThan(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Ge, true), () => Expression.LessThanOrEqual(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Lt, true), () => Expression.GreaterThan(memberExpression, propertyValue) },
{ new KeyValuePair<Operator, bool>(Operator.Le, true), () => Expression.GreaterThanOrEqual(memberExpression, propertyValue) },
};
var body = operatorMatrix[new KeyValuePair<Operator, bool>(fieldPredicate.Operator, fieldPredicate.Not)].Invoke();
return Expression.Lambda<Func<T, bool>>(body, parameterExpression);
}
}
PredicateBuilder
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
}
LikeExpression
public static class LikeExpression
{
private static readonly MethodInfo ApplyLikeMethodInfo = typeof(LikeExpression).GetMethod("ApplyLike");
private static readonly MethodInfo ApplyLikeNoCaseMethodInfo = typeof(LikeExpression).GetMethod("ApplyLikeNoCase");
private static readonly MethodInfo ApplyNotLikeMethodInfo = typeof(LikeExpression).GetMethod("ApplyNotLike");
private static readonly MethodInfo ApplyNotLikeNoCaseMethodInfo = typeof(LikeExpression).GetMethod("ApplyNotLikeNoCase");
public static Expression Like(Expression lhs, Expression pattern, bool caseSensitive = false)
{
return caseSensitive
? Expression.Call(ApplyLikeMethodInfo, lhs, pattern)
: Expression.Call(ApplyLikeNoCaseMethodInfo, lhs, pattern);
}
public static Expression NotLike(Expression lhs, Expression pattern, bool caseSensitive = false)
{
return caseSensitive
? Expression.Call(ApplyNotLikeMethodInfo, lhs, pattern)
: Expression.Call(ApplyNotLikeNoCaseMethodInfo, lhs, pattern);
}
public static bool ApplyLike(string text, string likePattern)
{
string pattern = PatternToRegex(likePattern);
return Regex.IsMatch(text, pattern, RegexOptions.None);
}
public static bool ApplyLikeNoCase(string text, string likePattern)
{
string pattern = PatternToRegex(likePattern);
return Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase);
}
public static bool ApplyNotLike(string text, string likePattern)
{
string pattern = PatternToRegex(likePattern);
return !Regex.IsMatch(text, pattern, RegexOptions.None);
}
public static bool ApplyNotLikeNoCase(string text, string likePattern)
{
string pattern = PatternToRegex(likePattern);
return !Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase);
}
public static string PatternToRegex(string pattern)
{
pattern = Regex.Escape(pattern);
pattern = pattern.Replace("%", @".*");
pattern = $"^{pattern}$";
return pattern;
}
}
CompositeIterator
public class CompositeIterator<T>
{
private Expression<Func<T, bool>> finalQuery;
private Expression<Func<T, bool>> higherQuery;
private GroupOperator? previousOperator;
private int level = -1;
public Expression<Func<T, bool>> Prepare(PredicateGroup predicateGroup)
{
previousOperator = predicateGroup.Operator;
finalQuery = t => predicateGroup.Operator == GroupOperator.And;
CallRecursive(predicateGroup);
return finalQuery;
}
private void CallRecursive(PredicateGroup predicateGroup)
{
var nodes = predicateGroup.Predicates;
bool isSet = true;
++level;
foreach (var n in nodes)
{
if (n is PredicateGroup @group)
{
CallRecursive(@group);
--level;
}
else
{
var expr = PredicateParser<T>.Parse((IFieldPredicate)n);
if (level > 0)
{
if (isSet)
{
higherQuery = t => predicateGroup.Operator == GroupOperator.And;
isSet = false;
}
higherQuery = predicateGroup.Operator == GroupOperator.And
? higherQuery.And(expr)
: higherQuery.Or(expr);
}
else
{
previousOperator = predicateGroup.Operator;
finalQuery = predicateGroup.Operator == GroupOperator.And
? finalQuery.And(expr)
: finalQuery.Or(expr);
}
}
}
if (higherQuery != null)
{
finalQuery = previousOperator == GroupOperator.And
? finalQuery.And(higherQuery)
: finalQuery.Or(higherQuery);
}
higherQuery = null;
}
}