我需要帮助才能完成此查询。我需要使用表达式,以便我可以动态地处理查询。换句话说,用户构建了推入其中的查询参数。我需要专门处理行Type yourType = typeof(YourGeneric);
中引用的泛型类型的帮助,& ParameterExpression pe = Expression.Parameter(yourType, "x");
& Expression left = Expression.Property(pe, yourType.GetProperty(wheres[i].ColumnName))
..完全披露,我是通过另一个推荐而做的,并不完全理解泛型。有关详细信息,请参阅Entity Framework Dynamic Where Clause from List<object>。
Expression query;
for (int i = 0; i < wheres.Count; i++)
{
Type yourType = typeof(YourGeneric);
ParameterExpression pe = Expression.Parameter(yourType, "x");
Expression left = Expression.Property(pe, yourType.GetProperty(wheres[i].ColumnName));
Expression right = Expression.Constant(wheres[i].Value, typeof(int));
Expression result = getOperatorExp(wheres[i].Operator, left, right);
if (i == 0)
{
query = result;
}
else
{
Expression grammer = getGrammerExp(wheres[i].AndOr, query, result);
query = grammer;
}
}
MasterQuery.Where(query);
public Expression getOperatorExp(string Operator, Expression left, Expression right)
{
Expression exp;
switch (Operator.ToUpper())
{
case "Equals":
exp = Expression.Equal(left, right);
break;
case "NOT EQUALS":
exp = Expression.NotEqual(left, right);
break;
case "LESS THAN":
exp = Expression.LessThan(left, right);
break;
case "LESS THAN OR EQUALS":
exp = Expression.LessThanOrEqual(left, right);
break;
case "GREATER THAN":
exp = Expression.GreaterThan(left, right);
break;
case "GREATER THAN OR EQUALS":
exp = Expression.GreaterThanOrEqual(left, right);
break;
case "ON":
exp = Expression.Equal(left, right);
break;
case "BEFORE":
exp = Expression.LessThan(left, right);
break;
case "ON OR BEFORE":
exp = Expression.LessThanOrEqual(left, right);
break;
case "AFTER":
exp = Expression.GreaterThan(left, right);
break;
case "ON OR AFTER":
exp = Expression.GreaterThanOrEqual(left, right);
break;
default:
exp = Expression.Equal(left, right);
break;
}
return exp;
}
public Expression getGrammerExp(string AndOr, Expression left, Expression right)
{
Expression exp;
switch (AndOr.ToUpper())
{
case "AND":
exp = Expression.And(left, right);
break;
case "OR":
exp = Expression.Or(left, right);
break;
case "":
exp = Expression.LessThan(left, right);
break;
default:
exp = Expression.Equal(left, right);
break;
}
return exp;
}
答案 0 :(得分:1)
YourGeneric应该是您要查询的实体类型。例如,如果在DbContext中有一组Cities(DbSet Cities),则应将该类型作为通用类型传递。
您不希望为上下文中的每个实体类型编写自定义代码。您编写的代码应该适用于查询Cities表和查询Fruits表。因此 - 使用泛型。
举个例子:
ParameterExpression pe = Expression.Parameter(typeof(City), "x");
将为City类型的lambda参数创建表达式,该表达式可用于查询该类型的集合。为了使代码可以重复使用,你可以使它具有通用性(如你的问题中所述)以及这些内容:
public Expression CreateExpression<TEntity, TConst>(WhereClause singleWhere)
{
Type entityType = typeof(TEntity);
ParameterExpression pe = Expression.Parameter(entityType, "x");
Expression left = Expression.Property(pe,
entityType.GetProperty(singleWhere.ColumnName));
Expression right = Expression.Constant(singleWhere.Value, typeof(TConst));
return getOperatorExp(singleWhere.Operator, left, right);
}
然后您可以在调用中传递适当的类型,如下所示:
Expression result = CreateExpression<City, int>();
这允许您传递不同类型的实体和不同类型的常量来查询每次调用。
此外,这应该是大写:
case "Equals":
如果您的代码示例可以在某种程度上进行编译将会很好 - 这会让我更容易为您提供工作样本。 .NET中的表达式树是一个比泛型更复杂的主题。
答案 1 :(得分:1)
这就是我的实施情况。
测试代码:
var masterQuery = new[]
{
new { Name = "Asterix", Weight = 50 },
new { Name = "Obelix", Weight = 120 },
new { Name = "Idefix", Weight = 1 }
}.AsQueryable();
var wheres = new[]
{
new Filtering.WhereParams { ColumnName = "Name", Operator = "Equals", Value = "Asterix" },
new Filtering.WhereParams { AndOr = "OR", ColumnName = "Name", Operator = "Equals", Value = "Obelix" },
new Filtering.WhereParams { AndOr = "AND", ColumnName = "Weight", Operator = "LESS THAN", Value = 100 }
};
var filtered = masterQuery.Where(wheres).ToList();
// asterix
以下是实施:
public static class Filtering
{
public class WhereParams
{
public string ColumnName { get; set; }
public object Value { get; set; }
public string Operator { get; set; }
public string AndOr { get; set; }
}
/// <summary>
/// Make a predicate from the specified <paramref name="wheres"/>.
/// </summary>
public static Expression<Func<T, bool>> ToPredciate<T>(this IEnumerable<WhereParams> wheres)
{
using (var e = wheres.GetEnumerator())
{
if (!e.MoveNext()) // not filtered
return x => true;
var pe = Expression.Parameter(typeof(T), "x");
var body = GetComparePredicateBody(pe, e.Current); // first condition
// join body with more conditions
while (e.MoveNext())
{
var right = GetComparePredicateBody(pe, e.Current);
switch (e.Current.AndOr)
{
case "AND":
body = Expression.AndAlso(body, right);
break;
case "OR":
body = Expression.OrElse(body, right);
break;
default:
// LessThan and Equal don't make much sense on booleans, do they?
throw new Exception("Bad boolean operator.");
}
}
return Expression.Lambda<Func<T, bool>>(body, pe);
}
}
/// <summary>
/// Returns a boolean expression x.ColumnName op Value.
/// </summary>
private static Expression GetComparePredicateBody(Expression x, WhereParams where)
{
var left = Expression.Property(x, where.ColumnName);
var right = Expression.Constant(where.Value);
switch (where.Operator)
{
case "Equals": return Expression.Equal(left, right);
case "LESS THAN": return Expression.LessThan(left, right);
// ...
default: throw new ArgumentException("Bad comparison operator.");
}
}
public static IQueryable<T> Where<T>(this IQueryable<T> source, IEnumerable<WhereParams> wheres) => source.Where(wheres.ToPredciate<T>());
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, IEnumerable<WhereParams> wheres) => source.Where(wheres.ToPredciate<T>().Compile());
}