2011-04-08 90 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的介紹。