2012-01-23 14 views
13

Sto provando a creare un'espressione lambda che verrà combinata con altri in un albero di espressioni piuttosto grande per il filtro. Funziona bene fino a quando non ho bisogno di filtrare da una proprietà di sub-raccolta.Creazione di un albero di espressioni dinamiche per filtrare su una proprietà di raccolta

Come si costruisce un'espressione Lambda che filtra utilizzando Any() su una proprietà di una raccolta che è una proprietà dell'oggetto root?

Esempio:

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

Questo è come vorrei costruire l'espressione in modo statico, ma ho bisogno di costruire in modo dinamico. Dispiace per la confusione.

Edit: Ecco un frammento di come gestire le espressioni meno complicate:

IQueryable<Office> officeQuery = CurrentDataSource.Offices.AsQueryable<Office>(); 
ParameterExpression pe = Expression.Parameter(typeof(Office), "Office"); 
ParameterExpression tpe = Expression.Parameter(typeof(Trades), "Trades"); 

Expression SimpleWhere = null; 
Expression ComplexWhere = null; 
foreach (ServerSideFilterObject fo in ssfo) 
{ 
    SimpleWhere = null; 
    foreach (String value in fo.FilterValues) 
    { 
     if (!CollectionProperties.Contains(fo.PropertyName)) 
     { 
      //Handle singleton lambda logic here. 
      Expression left = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); 
      Expression right = Expression.Constant(value); 
      if (SimpleWhere == null) 
      { 
       SimpleWhere = Expression.Equal(left, right); 
      } 
      else 
      { 
       Expression e1 = Expression.Equal(left, right); 
       SimpleWhere = Expression.Or(SimpleWhere, e1); 
      } 
     } 
     else 
     { 
      //handle inner Collection lambda logic here. 
      Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); 
      Expression right = Expression.Constant(value); 
      Expression InnerLambda = Expression.Equal(left, right); 

      //Problem area. 
      Expression OfficeAndProperty = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); 
      Expression OuterLambda = Expression.Call(OfficeAndProperty, typeof(Trades).GetMethod("Any", new Type[] { typeof(Expression) }),InnerLambda); 

      if (SimpleWhere == null) 
       SimpleWhere = OuterLambda; 
      else 
       SimpleWhere = Expression.Or(SimpleWhere, OuterLambda); 
     } 
    } 
    if (ComplexWhere == null) 
     ComplexWhere = SimpleWhere; 
    else 
     ComplexWhere = Expression.And(ComplexWhere, SimpleWhere); 
} 
MethodCallExpression whereCallExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { officeQuery.ElementType }, officeQuery.Expression, Expression.Lambda<Func<Office, bool>>(ComplexWhere, new ParameterExpression[] { pe })); 
results = officeQuery.Provider.CreateQuery<Office>(whereCallExpression); 
+0

Stai chiedendo come costruire un albero di espressioni? – SLaks

+0

Non sono sicuro di come la gerarchia funzioni nel tuo esempio. Puoi approfondire un po 'su questo? Uffici è la radice e quindi ogni ufficio ha una raccolta di mestieri? E vuoi filtrare il nome del trade ?? Il filtro è dove sono un po 'perso. Scusate. –

+0

No, non sono sicuro della sintassi utilizzata per creare un'espressione con una chiamata di metodo interna e un'espressione per un parametro. In questo caso, viene visualizzato un errore che indica che Any() non può essere trovato perché i miei parametri non corrispondono alla definizione. In questo caso non sono sicuro che sia perché non sono sintonizzato sulla sintassi o se Any() non è supportato nel modo in cui lo sto usando. – George

risposta

9

trovato la soluzione. Non stavo cercando il metodo nel posto giusto prima.

Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); 
Expression right = Expression.Constant(value); 
Expression InnerLambda = Expression.Equal(left, right); 
Expression<Func<Trades, bool>> innerFunction = Expression.Lambda<Func<Trades, bool>>(InnerLambda, tpe); 

method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(Trades)); 
OuterLambda = Expression.Call(method, Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)),innerFunction); 
0

Quello che avete elencato come esempio funziona in base a un commento. Ecco un esempio di quello che ho lavorare con:

Templates.Where(t => t.TemplateFields.Any(f => f.Required == 'Y')) 

Abbiamo modelli che hanno raccolta specifica di campi, e quei campi potrebbe essere richiesto. Quindi posso ottenere i modelli in cui qualsiasi campo è richiesto da quella dichiarazione di cui sopra.

Speriamo che questo aiuti ... o almeno confermi quello che stai cercando di fare. Fatemi sapere se avete altre domande su questo e io elaborerò.

Buona fortuna!

+0

Questo è simile a quello con cui sto lavorando, ma devo creare l'espressione lamda in modo dinamico con il riflesso in modo da poter garantire che il filtro incorpori gli altri filtri nel set. – George

0

Il codice fornito

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

dovrebbe funzionare, a patto che o.base_Trades implementa IEnumerable<Trade>. Se o.base_Trades implementa solo IEnumerable, è necessario utilizzare Cast<Trade>() se si è sicuri che tutti gli elementi in o.base_Trades sono del tipo Trade o OfType<Trade>() se potrebbero esserci elementi di altri tipi (incompatibili).

Questo sarebbe quindi simile a questa:

CurrentDataSource.Offices 
    .Where(o => o.base_Trades.Cast<Trade>.Any(t => t.Name == "test")) 
1

Si prega di non fare questo, quello che vuoi veramente utilizzare una libreria chiamata dinamica linq. http://nuget.org/packages/DynamicLINQ

È possibile archiviare le query come stringhe e supporta query molto complesse. Gli alberi delle espressioni sono un incubo.

+0

che è una libreria eccellente, anch'io lo uso, ma non supporta, ad esempio, l'ordinamento su una proprietà di una proprietà di raccolta come 'myIQueryable.OrderBy (x => x.MyCollection.Select (y => y.Myproperty)) ', almeno non riesco a farlo funzionare –

Problemi correlati