2013-08-19 14 views
16

Ho una variabile denominata sortColumn, che contiene il testo di una colonna con cui voglio ordinare un risultato della query. Ho anche un repository generico che accetta come parametro un'Espressione che contiene il campo che voglio ordinare. Non riesco a passare dal nome della proprietà stringa a un'espressione.Crea espressione generica dal nome della proprietà di stringa

Così il repository generico che ho contiene il seguente metodo di

public IEnumerable<TEntity> Get<TOrderBy>(Expression<Func<TEntity, bool>> criteria, 
              Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, 
              int pageSize, 
              bool isAssendingOrder = true, 
              EnumDeletePolicy deletePolicy = EnumDeletePolicy.ExcludeDeleted) 

Avviso il secondo parametro a questo Get è Expression-func-TEntity, TOrderBy. Come ho già detto, ho una variabile chiamata sortColumn, che contiene la stringa per una proprietà sul mio oggetto TEntity. Devo convertire questa stringa in un'espressione che posso passare al metodo Get.

Ecco quello che ho adesso.

 var parameter = Expression.Parameter(typeof(IContract)); 
     var memberExpression = Expression.Property(parameter, data.SortColumn); 
     var lambdaExpression = Expression.Lambda(memberExpression, parameter); 

Che crea un oggetto di tipo LambdaExpression. Il tipo effettivo di questa espressione lambda è un Expression-Func-IContract, una stringa (o qualunque sia il tipo sortColumn della proprietà). Se chiamo il metodo Get e passo in LambdaExpression e lo lancio esplicitamente nel tipo Expression, funzionerà correttamente. Il problema è che non so quale sia il tipo di espressione, potrebbe essere una stringa, int, int ?, ecc. Tutto dipende dal tipo di proprietà che è specifica nella proprietà sortColumn.

Puoi aiutarmi a eseguire questo ultimo salto a destra nel tipo di espressione?

Modifica basata sui suggerimenti di Marc: Ho quasi questo funzionamento, in realtà basato specificamente sulla domanda che sta funzionando, ma ho 1 problema rimanente.

L'IContract che è il tipo di entità su cui sto interrogando effettivamente eredita da IRelationship. Se si specifica un campo dall'interfaccia IContract, il codice sopra funziona. Se si specifica un campo dall'interfaccia IRelationship, la seguente riga fallisce.

 var memberExpression = Expression.Property(parameter, data.SortColumn); 

Se provo qualcosa di simile di seguito in modo che sto afferrando il MemberExpression dal IRelationship, ma la costruzione del Lambda sulla base di IContract ottengo un errore dal repository.

 var parameter = Expression.Parameter(typeof(IRelationship)); 
     var memberExpression = Expression.Property(parameter, data.SortColumn); 
     var orderBy = Expression.Lambda(memberExpression, Expression.Parameter(typeof(IContract))); 

L'errore che ottengo è "il parametro '' non è stato rilegato in LINQ to Entities specificato interrogare espressione".

L'espressione finale per farlo funzionare è stato questo

 var parameter = Expression.Parameter(typeof(IContract)); 
     var memberExpression = Expression.Property(parameter, typeof(IRelationship), data.SortColumn); 
     var orderBy = Expression.Lambda(memberExpression, parameter); 

quindi avevo bisogno di specificare il parametro centrale per la linea memberExpression, a dire guardare nell'interfaccia relazione ereditato per la proprietà

+0

Che cosa vuoi fare con l'espressione? Ci sono modi per usare 'dynamic' per farlo girare nel sovraccarico generico più appropriato, in pratica evitando' MakeGenericMethod'. Qualche uso? Ad esempio: 'IQueryable filtered = Queryable.Where (source, (dynamic) expression);' –

risposta

17

È un pò è necessario utilizzare il sovraccarico generico corretto, che indicava che si doveva usare MakeGenericMethod; tuttavia, è anche possibile utilizzare dynamic per evitare la necessità di utilizzare MakeGenericMethod qui, per esempio (in questo caso tramite Where, ma il punto importante è come funziona):

IQueryable<Foo> source = new[] { new Foo { Bar = 123 } }.AsQueryable(); 
Expression<Func<Foo,bool>> typed = x=>x.Bar == 123; 

LambdaExpression untyped = typed; 
IQueryable<Foo> filtered = Queryable.Where(source, (dynamic)untyped); 

Nota: non è possibile utilizzare estensione metodi qui - quindi perché è necessario utilizzare Queryable.*.

Per un OrderBy esempio, utilizzando il codice:

var parameter = Expression.Parameter(typeof(Foo)); 
var memberExpression = Expression.Property(parameter, "Bar"); 
var lambdaExpression = Expression.Lambda(memberExpression, parameter); 
LambdaExpression untyped = lambdaExpression; 

IQueryable<Foo> sorted = Queryable.OrderBy(source, (dynamic)untyped); 

var all = sorted.ToArray(); 

Re di modifica:

var parameter = Expression.Parameter(typeof(IRelationship)); 
var memberExpression = Expression.Property(
    Expression.Convert(parameter, typeof(IContract)), data.SortColumn); 
var orderBy = Expression.Lambda(memberExpression, parameter); 
+0

Ma il metodo che ho bisogno di chiamare richiede un'espressione: Func non è una dinamica, quindi non posso passare in una dinamica. –

+0

@PaulCavacas 'Queryable.Where' e' Queryable.OrderBy' * anche * accettano un'espressione-Func, non una dinamica; non è un problema Il punto è che l'uso di 'dynamic' qui * lo fa funzionare *. Magia. –

+0

Ho quasi funzionato. Un problema rimanente. Se domanda per ulteriori dettagli. –

Problemi correlati