我正在根据各种搜索条件动态创建LINQ查询。
作为一个例子,假设我正在搜索Automobiles表,我可以选择按等级进行过滤。我有两个控件:
因此,用户可以选择比较类型[至少]和值3,我的代码需要创建一个查询,将结果限制为大于或等于3的汽车评级。
我在问题How to implement search functionality in C#/ASP.NET MVC中找到了VinayC给出的一个很好的解决方案。他的DynamicWhere()
方法动态地创建了可以生成正确过滤器的表达式的一部分。
我的问题是我的主要查询类型是汽车,但我的评级是在一个单独的表(Automobile.Ratings)中。我如何实现相同的技术并过滤我的主要查询类型以外的类型?
感谢您的任何提示。
答案 0 :(得分:2)
由于您拥有的操作数量很少,有限且在comiple时间已知,因此您只需使用switch
处理它:
IQueryable<Something> query = GetQuery();
int ratingToComareWith = 1;
string operation = "Equal";
switch (operation)
{
case ("Equal"):
query = query.Where(item => item == ratingToComareWith);
break;
case ("Less Than"):
query = query.Where(item => item < ratingToComareWith);
break;
}
答案 1 :(得分:0)
这是表达式构建的实体框架友好替代方案。当然,您需要验证column
和op
以防止SQL注入。
// User provided values
int value = 3;
string column = "Rating";
string op = "<";
// Dynamically built query
db.Database.SqlQuery<Automobile>(@"select distinct automobile.* from automobile
inner join ratings on ....
where [" + column + "] " + op + " @p0", value);
答案 2 :(得分:0)
Here是一种为linq-to-entities的嵌套集合或类型构建条件的方法。 根据您的需求进行重组:
public static Expression GetCondition(Expression parameter, object value, OperatorComparer operatorComparer, params string[] properties)
{
Expression resultExpression = null;
Expression childParameter, navigationPropertyPredicate;
Type childType = null;
if (properties.Count() > 1)
{
//build path
parameter = Expression.Property(parameter, properties[0]);
var isCollection = typeof(IEnumerable).IsAssignableFrom(parameter.Type);
//if it´s a collection we later need to use the predicate in the methodexpressioncall
if (isCollection)
{
childType = parameter.Type.GetGenericArguments()[0];
childParameter = Expression.Parameter(childType, childType.Name);
}
else
{
childParameter = parameter;
}
//skip current property and get navigation property expression recursivly
var innerProperties = properties.Skip(1).ToArray();
navigationPropertyPredicate = GetCondition(childParameter, test, innerProperties);
if (isCollection)
{
//build methodexpressioncall
var anyMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == "Any" && m.GetParameters().Length == 2);
anyMethod = anyMethod.MakeGenericMethod(childType);
navigationPropertyPredicate = Expression.Call(anyMethod, parameter, navigationPropertyPredicate);
resultExpression = MakeLambda(parameter, navigationPropertyPredicate);
}
else
{
resultExpression = navigationPropertyPredicate;
}
}
else
{
var childProperty = parameter.Type.GetProperty(properties[0]);
var left = Expression.Property(parameter, childProperty);
var right = Expression.Constant(value,value.GetType());
if(!new List<OperatorComparer> {OperatorComparer.Contains,OperatorComparer.StartsWith}.Contains(operatorComparer))
{
navigationPropertyPredicate = Expression.MakeBinary((ExpressionType)operatorComparer,left, right);
}
else
{
var method = GetMethod(childProperty.PropertyType, operatorComparer); //get property by enum-name from type
navigationPropertyPredicate = Expression.Call(left, method, right);
}
resultExpression = MakeLambda(parameter, navigationPropertyPredicate);
}
return resultExpression;
}
private static MethodInfo GetMethod(Type type,OperatorComparer operatorComparer)
{
var method = type.GetMethod(Enum.GetName(typeof(OperatorComparer),operatorComparer));
return method;
}
public enum OperatorComparer
{
Equals = ExpressionType.Equal,
Contains,
StartsWith,
GreaterThan = ExpressionType.GreaterThan
....
}
private static Expression MakeLambda(Expression parameter, Expression predicate)
{
var resultParameterVisitor = new ParameterVisitor();
resultParameterVisitor.Visit(parameter);
var resultParameter = resultParameterVisitor.Parameter;
return Expression.Lambda(predicate, (ParameterExpression)resultParameter);
}
private class ParameterVisitor : ExpressionVisitor
{
public Expression Parameter
{
get;
private set;
}
protected override Expression VisitParameter(ParameterExpression node)
{
Parameter = node;
return node;
}
}
}
如果需要,可以用params Expression(Func(T,object))替换params string []。需要更多的工作才能这样做。您需要使用类似
的语法来定义嵌套集合item => item.nestedCollection.Select(nested => nested.Property)
并在表达式访问者的帮助下重写表达式。