2011-04-08 89 views
20

我有这样的SQL语句动态添加的where子句中的实体框架

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') 

HHO可我实现使用LINQ与实体框架这种说法?

+0

Syed Mehroz Alam的这篇博客文章包含了几个非常详尽的例子,它展示了如何以一种有用的方式将LINQ查询语法与方法语法相结合:[LINQ:如何使用延迟执行和匿名类型构建复杂查询] (http://smehrozalam.wordpress.com/2010/04/06/linq-how-to-build-complex-queries-utilizing-deferred-execution-and-anonymous-types/) – 2013-05-21 20:07:56

回答

26

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

var pr = PredicateBuilder.False<User>(); 
foreach (var name in names) 
{ 
    pr = pr.Or(x => x.Name == name && x.Username == name); 
} 
return query.AsExpandable().Where(pr); 
+1

我已经检查过此代码之前。据我记得这段代码不适用于实体,只适用于LINQ到SQL数据模型。 “我不确定,你有没有用过?” – Mironline 2011-04-08 13:08:44

+0

是的,它支持EF。即使在nHibernate中也使用它,这非常棒。 – 2011-04-08 13:10:45

+2

亲爱的HeavyWave:我再次检查过,但得到了这个异常“LINQ to Entities不支持LINQ表达式节点类型'Invoke'。”你有什么想法吗? – Mironline 2011-04-08 13:17:47

2

不要忘记,实体框架也理解entity sql,所以你可以在字符串中执行这部分查询。当你有动态的东西时,建立一个字符串是非常方便的。

4

注意:这是从我有的东西修改,所以它可能无法正常工作。但这将是一个很好的起点。

public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> source, 
                IEnumerable<WhereSpecifier> 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<TEntity>(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<TEntity>(resultExp); 
    } 

GenerateSelector:

public static Expression GenerateSelector<TEntity>(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); 
4
Expression<Func<User, bool>> whereExpression = null; 
foreach (var name in names) 
{ 
    Expression<Func<User, bool>> e1 = u => u.Name == name; 
    Expression<Func<User, bool>> 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<Func<T, bool>> And<T>(this Expression<Func<T, bool>> leftExpression, Expression<Func<T, bool>> 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<Func<T, bool>>(exprBody, paramExpr); 
    } 

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> leftExpression, Expression<Func<T, bool>> 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<Func<T, bool>>(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; 
    } 
} 
2

我试了@埃戈帕夫利欣解决方案,但我得到了"The LINQ expression node type 'Invoke' is not supported in LINQ to Entities."

根据this你可以使用PredicateExtensions

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

我必须动态地根据用户界面的选择,构建断言对于“去哪儿”的条款。 'System.Dynamic.Linq'允许来自字符串的谓词。

foreach (var name in names) 
{ 
    query = query.Where("[email protected] And [email protected]", name, name); 
} 
return query; 

'System.Dynamic.Linq'可作为nuget包使用。看看Scott Guthrie对主题here的介绍。