Sto cercando di creare una clausola where per la mia vista usando LINQ.
Sono stato in grado di creare una singola colonna dove clausola e vorrei ora creare più colonne in cui clausole ..
Ho visto il codice da implementare in .Net 4 e versioni successive, ma dato che devo usare .Net 3.5, ho bisogno di un rapido intervento per questo. quindi quello che sto cercando di fare è ....
Expression leftexp = {tag=>((tag.id=2)||(tag.id=3))}
Expression rightexp = {tag=>((tag.uid="MU")||(tag.uid="ST"))}
da queste due espressioni che vorrei creare
BinaryExpression be = {tag=>((tag.id=2)||(tag.id=3))} &&
{tag=>((tag.uid="MU")||(tag.uid="ST"))}
qualcosa del genere che potrei passare alla mia clausola in LINQ.
Ho provato a usare Expression.End (leftexp, rightexp)
ma ha ottenuto l'errore ..
L'operatore binario E non è definito per i tipi
'System.Func2[WebApplication1.View_MyView,System.Boolean]' and 'System.Func
2 [WebApplication1.View_MyView, System.Boolean]'.
Expression è nuovo per me e potrebbe aver guardato troppo del codice in modo un po 'confuso su come fare per farlo ... sarebbe davvero grato se tu potessi indicarmi la giusta direzione.
Non puoi farlo senza riscrivere entrambi gli alberi di espressione completi in uno completamente nuovo.
Motivo: gli oggetti espressione-parametro devono essere uguali per l'intero albero di espressioni. Se si combinano i due, si hanno due oggetti espressione-parametro per lo stesso parametro, che non funzioneranno.
Mostra con il seguente codice:
Expression<Func<Tab, bool>> leftexp = tag => ((tag.id == 2) || (tag.id == 3));
Expression<Func<Tab, bool>> rightexp = tag => ((tag.uid == "MU") || (tag.uid == "ST"));
Expression binaryexp = Expression.AndAlso(leftexp.Body, rightexp.Body);
ParameterExpression[] parameters = new ParameterExpression[1] {
Expression.Parameter(typeof(Tab), leftexp.Parameters.First().Name)
};
Expression<Func<Tab, bool>> lambdaExp = Expression.Lambda<Func<Tab, bool>>(binaryexp, parameters);
var lambda = lambdaExp.Compile();
Questo fallisce sulla chiamata lambdaExp.Compile (), che fornisce la seguente eccezione:
Lambda Parameter not in scope
Questo è causato dal fatto che in pratica sto riutilizzando l'espressione leftexp e rightexp, ma hanno espressioni parametro diverse, che non sono da me date Expression.Lambda<Func<Tab>>(...)
chiamata. In profondità nel leftexp e rightexp ci sono oggetti espressione-parametro che devono corrispondere a quello dato alla chiamata Expression.Lambda<Func<Tab>>(...)
.
Per risolvere questo problema, è necessario ricreare l'espressione completa utilizzando una nuova espressione di parametro (singola) per il tag di parametro.
Vedi qui per maggiori informazioni sul problema.
La riscrittura delle espressioni è stata semplificata con l'aggiunta di ExpressionVisitor a BCL. Con alcuni aiutanti l'attività diventa quasi banale.
Ecco una classe di visitatori che utilizzo per applicare un delegato ai nodi dell'albero:
internal sealed class ExpressionDelegateVisitor : ExpressionVisitor {
private readonly Func<Expression , Expression> m_Visitor;
private readonly bool m_Recursive;
public static Expression Visit ( Expression exp , Func<Expression , Expression> visitor , bool recursive ) {
return new ExpressionDelegateVisitor ( visitor , recursive ).Visit ( exp );
}
private ExpressionDelegateVisitor ( Func<Expression , Expression> visitor , bool recursive ) {
if ( visitor == null ) throw new ArgumentNullException ( nameof(visitor) );
m_Visitor = visitor;
m_Recursive = recursive;
}
public override Expression Visit ( Expression node ) {
if ( m_Recursive ) {
return base.Visit ( m_Visitor ( node ) );
}
else {
var visited = m_Visitor ( node );
if ( visited == node ) return base.Visit ( visited );
return visited;
}
}
}
Ed ecco i metodi di supporto per semplificare la riscrittura:
public static class SystemLinqExpressionsExpressionExtensions {
public static Expression Visit ( this Expression self , Func<Expression , Expression> visitor , bool recursive = false ) {
return ExpressionDelegateVisitor.Visit ( self , visitor , recursive );
}
public static Expression Replace ( this Expression self , Expression source , Expression target ) {
return self.Visit ( x => x == source ? target : x );
}
public static Expression<Func<T , bool>> CombineAnd<T> ( this Expression<Func<T , bool>> self , Expression<Func<T , bool>> other ) {
var parameter = Expression.Parameter ( typeof ( T ) , "a" );
return Expression.Lambda<Func<T , bool>> (
Expression.AndAlso (
self.Body.Replace ( self.Parameters[0] , parameter ) ,
other.Body.Replace ( other.Parameters[0] , parameter )
) ,
parameter
);
}
}
Ciò consente di combinare espressioni come questa:
static void Main () {
Expression<Func<int , bool>> leftExp = a => a > 3;
Expression<Func<int , bool>> rightExp = a => a < 7;
var andExp = leftExp.CombineAnd ( rightExp );
}
AGGIORNARE:
Nel caso in cui ExpressionVisitor
non sia disponibile, la sua fonte era stata pubblicata qualche tempo fa qui . La nostra libreria ha utilizzato tale implementazione fino alla migrazione a .NET 4.