2011-04-08 21 views
20

में गतिशील रूप से जहां खंड जोड़े मैं इस एसक्यूएल बयान हैइकाई की रूपरेखा

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

सैयद मेहरोज आलम द्वारा इस ब्लॉग पोस्ट में कई उदाहरण हैं जो बहुत अच्छी तरह से हैं, और यह दिखाता है कि कैसे LINQ क्वेरी सिंटैक्स को विधि सिंटैक्स के साथ उपयोगी तरीके से जोड़ना है: [LINQ: स्थगित निष्पादन और अनाम प्रकारों का उपयोग करने वाले जटिल प्रश्नों को कैसे बनाएं] (http://smehrozalam.wordpress.com/2010/04/06/linq-how-to-build-complex-queries-utilizing-deferred-execution-and-anonymous-types/) –

उत्तर

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

मैंने पहले इस कोड को चेक किया है । जहां तक ​​मुझे याद है कि यह कोड इकाई के साथ काम नहीं करता है, केवल SQL मॉडल के साथ linq के साथ काम करता है। "मुझे इसके बारे में निश्चित नहीं है। क्या आपने इसके साथ काम किया है?" – Mironline

+0

हां, यह ईएफ का समर्थन करता है। मैं इसे nHibernate के साथ भी उपयोग करता हूं, यह शानदार है। –

+2

प्रिय हेवीवेव: मैंने फिर से जांच की है, लेकिन यह अपवाद मिला है "LINQ अभिव्यक्ति नोड प्रकार 'Invoke' LINQ से Entities में समर्थित नहीं है।" क्या आपको इसके बारे में कोई विचार है? – Mironline

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 पैकेज के रूप में उपलब्ध है। स्कॉट गुथरी के विषय here पर परिचय देखें।

संबंधित मुद्दे