在Entity Framework中动态添加where子句

我有这个sql语句

SELECT userID from users WHERE (name='name1' AND username='username1') OR (name='name2' AND username='username2') OR (name='name3' AND username='username3') OR .......... (name='nameN' AND username='usernameN') 

我可以使用LINQ在entity framework中实现此语句吗?

你可以使用一种叫做PredicateBuilder的漂亮东西。 像这样使用它

 var pr = PredicateBuilder.False(); foreach (var name in names) { pr = pr.Or(x => x.Name == name && x.Username == name); } return query.AsExpandable().Where(pr); 
  Expression> whereExpression = null; foreach (var name in names) { Expression> e1 = u => u.Name == name; Expression> andExpression = e1.And(u => u.Username == name); whereExpression = whereExpression == null ? andExpression : whereExpression.Or(andExpression); } return query.Where(whereExpression); 

这个助手可以帮到你。

 public static class ExpressionExtensions { public static Expression> And(this Expression> leftExpression, Expression> rightExpression) { if (leftExpression == null) return rightExpression; if (rightExpression == null) return leftExpression; var paramExpr = Expression.Parameter(typeof(T)); var exprBody = Expression.And(leftExpression.Body, rightExpression.Body); exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody); return Expression.Lambda>(exprBody, paramExpr); } public static Expression> Or(this Expression> leftExpression, Expression> rightExpression) { if (leftExpression == null) return rightExpression; if (rightExpression == null) return leftExpression; var paramExpr = Expression.Parameter(typeof(T)); var exprBody = Expression.Or(leftExpression.Body, rightExpression.Body); exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody); return Expression.Lambda>(exprBody, paramExpr); } } class ParameterReplacer : ExpressionVisitor { private readonly ParameterExpression _parameter; protected override Expression VisitParameter(ParameterExpression node) { return base.VisitParameter(_parameter); } internal ParameterReplacer(ParameterExpression parameter) { _parameter = parameter; } } 

注意:这是从我拥有的东西修改,所以它可能无法开箱即用。 但这将是一个很好的起点。

  public static IQueryable Where(this IQueryable source, IEnumerable orClauses) where TEntity : class { if (!orClauses.Any()) return source.Where(t => false); Type type = typeof (TEntity); ParameterExpression parameter = null; Expression predicate = Expression.Constant(false, typeof (bool)); ParameterExpression whereEnt = Expression.Parameter(type, "WhereEnt"); foreach (WhereSpecifier orClause in orClauses) { Expression selector; if (orClause.Selector != null) { selector = orClause.Selector; parameter = orClause.Parameter; } else { parameter = whereEnt; Type selectorResultType; selector = GenerateSelector(parameter, orClause.Column, out selectorResultType); } Expression clause = selector.CallMethod(orClause.Method, MakeConstant(selector.Type, orClause.Value), orClause.Modifiers); predicate = Expression.Or(predicate, clause); } var lambda = Expression.Lambda(predicate, whereEnt); var resultExp = Expression.Call(typeof (Queryable), "Where", new[] {type}, source.Expression, Expression.Quote(lambda)); return source.Provider.CreateQuery(resultExp); } 

GenerateSelector:

 public static Expression GenerateSelector(ParameterExpression parameter, string propertyName, out Type resultType) where TEntity : class { // create the selector part, but support child properties PropertyInfo property; Expression propertyAccess; if (propertyName.Contains('.')) { // support to be sorted on child fields. String[] childProperties = propertyName.Split('.'); property = typeof (TEntity).GetProperty(childProperties[0]); propertyAccess = Expression.MakeMemberAccess(parameter, property); for (int i = 1; i < childProperties.Length; i++) { property = property.PropertyType.GetProperty(childProperties[i]); propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); } } else { property = typeof (TEntity).GetProperty(propertyName); propertyAccess = Expression.MakeMemberAccess(parameter, property); } resultType = property.PropertyType; return propertyAccess; } 

WHereSpecifier:

 public class WhereSpecifier { public WhereSpecifier(string column, CheckMethod method, string value, CheckMethodModifiers modifiers) { Modifiers = modifiers; Value = value; Column = column; Method = method; } public WhereSpecifier(string column, CheckMethod method, string value) : this(column, method, value, CheckMethodModifiers.None) { } public Expression Selector { get; set; } public ParameterExpression Parameter { get; set; } public string Column { get; set; } public CheckMethod Method { get; set; } public CheckMethodModifiers Modifiers { get; set; } public string Value { get; set; } } 

用法:

 var column = typeof(TEntity).Name + "ID"; var where = from id in SelectedIds select new WhereSpecifier(column, CheckMethod.Equal, id.ToString()); return GetTable().Where(where); 

不要忘记entity framework也理解实体sql ,因此您可以在字符串中执行此部分查询。 当你需要做动态的东西时,构建一个字符串非常方便。

我尝试了@Egor Pavlikhin解决方案,但我得到了"The LINQ expression node type 'Invoke' is not supported in LINQ to Entities."

根据这个你可以使用PredicateExtensions :

 var predicate = PredicateExtensions.Begin(); foreach (var name in names) { pr = pr.Or(x => x.Name == name); } return _context.Users.Where(predicate); 

我必须根据用户界面选择动态地构造’Where’子句的谓词。 ‘System.Dynamic.Linq’允许从字符串中进行谓词。

 foreach (var name in names) { query = query.Where("Name=@0 And UserName=@1", name, name); } return query; 

‘System.Dynamic.Linq’可用作nuget包。 在这里查看Scott Guthrie对该主题的介绍。