2013-07-31 28 views
6

Sto avendo un problema simile che è stato chiesto qui: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expressionLINQ to Entities non riconosce il 'Nome metodo' metodo metodo

Sto cercando di impaginare la mia fonte, ma nel mio caso, posso 't mettere il risultato di GetPropertyValue in una variabile, perché ho bisogno x per farlo:

public IEnumerable<TModel> Paginate(IQueryable<TModel> source, ref int totalPages, int pageIndex, int pageSize, string sortfield, SortDirection? sortdir) 
{ 
    totalPages = (int)Math.Ceiling(source.Count()/(double)pageSize); 

    if (sortdir == SortDirection.Descending) 
    { 
     return source.OrderByDescending(x => GetPropertyValue(x, sortfield)).Skip(pageIndex * pageSize).Take(pageSize).ToList(); 
    } 
    else 
    { 
     return source.OrderBy(x => GetPropertyValue(x, sortfield)).Skip(pageIndex * pageSize).Take(pageSize).ToList(); 
    } 
} 

private static object GetPropertyValue(object obj, string name) 
{ 
    return obj == null ? null : obj.GetType().GetProperty(name).GetValue(obj, null); 
} 

Cosa potevo fare, in questo caso?

+0

cosa/dove esattamente sia il problema che stanno ottenendo? Sembra che il tuo ottenere un percorso non tutti restituisca un valore? – Sayse

+0

Ricevo un "LINQ su Entità che non riconosce il metodo Metodo metodo nome", in particolare il metodo "GetPropertyValue". –

risposta

6

Le espressioni lambda (quelle utilizzate in Dove, OrderBy ecc.) Non possono contenere alcun codice specifico C#, possono contenere solo albero di espressioni, che viene tradotto in SQL. Non è possibile chiamare lì metodi arbitrari, ad eccezione di quelli citati dalla documentazione EF come SqlFunctions ecc.

Per eseguire l'ordinamento con un nome di campo in fase di esecuzione, è necessario creare un'espressione lambda in fase di esecuzione e passarla sopra.

public IEnumerable<TModel> Paginate(IQueryable<TModel> source, ref int totalPages, int pageIndex, int pageSize, string sortfield, SortDirection? sortdir) 
{ 
    totalPages = (int)Math.Ceiling(source.Count()/(double)pageSize); 

    if (sortdir == SortDirection.Descending) 
    { 
     return source.OrderByDescending(sortfield).Skip(pageIndex * pageSize).Take(pageSize).ToList(); 
    } 
    else 
    { 
     return source.OrderBy(sortfield).Skip(pageIndex * pageSize).Take(pageSize).ToList(); 
    } 
} 


public static class QueryableHelper 
{ 
    public static IQueryable<TModel> OrderBy<TModel>(this IQueryable<TModel> q, string name) 
    { 
     Type entityType = typeof(TModel); 
     PropertyInfo p = entityType.GetProperty(name); 
     MethodInfo m = typeof(QueryableHelper).GetMethod("OrderByProperty").MakeGenericMethod(entityType, p.PropertyType); 
     return(IQueryable<TModel>) m.Invoke(null, new object[] { q, p }); 
    } 

    public static IQueryable<TModel> OrderByDescending<TModel>(this IQueryable<TModel> q, string name) 
    { 
     Type entityType = typeof(TModel); 
     PropertyInfo p = entityType.GetProperty(name); 
     MethodInfo m = typeof(QueryableHelper).GetMethod("OrderByPropertyDescending").MakeGenericMethod(entityType, p.PropertyType); 
     return (IQueryable<TModel>)m.Invoke(null, new object[] { q, p }); 
    } 

    public static IQueryable<TModel> OrderByPropertyDescending<TModel, TRet>(IQueryable<TModel> q, PropertyInfo p) 
    { 
     ParameterExpression pe = Expression.Parameter(typeof(TModel)); 
     Expression se = Expression.Convert(Expression.Property(pe, p), typeof(object)); 
     return q.OrderByDescending(Expression.Lambda<Func<TModel, TRet>>(se, pe)); 
    } 

    public static IQueryable<TModel> OrderByProperty<TModel, TRet>(IQueryable<TModel> q, PropertyInfo p) 
    { 
     ParameterExpression pe = Expression.Parameter(typeof(TModel)); 
     Expression se = Expression.Convert(Expression.Property(pe, p), typeof(object)); 
     return q.OrderBy(Expression.Lambda<Func<TModel, TRet>>(se, pe)); 
    } 
} 

Questa soluzione funziona solo su unico livello di proprietà, ma se si desidera che i livelli nidificati che ha bisogno di più lavoro, forse si può guardare dopo SDK, che fa tutto questo.

Tuttavia, se si dà un'occhiata a Entity REST SDK stesso, ha molte cose e tutte le cose che potrebbero essere necessarie. Disclaimer: I am the Author.

https://entityrestsdk.codeplex.com

+0

Quasi lavorato. Ora sto ricevendo un "Espressione di tipo" System.Int64 "non può essere utilizzato per il tipo di ritorno" System.Object "". Ho modificato 'Func >' in 'Func >' e ha funzionato, ma non conosco il tipo di oggetto che verrà passato alla funzione. Potrebbe essere un 'String', per esempio. Ad ogni modo per aggirare questo? –

+2

Puoi provare ora? L'ho modificato poco. Parto di casa per la giornata, se funziona alla grande, altrimenti cercherò di pubblicare una soluzione, che è poco più grande, ma sarà domani. –

+0

Non l'ho fatto, ma grazie mille per il vostro aiuto –

1

Invece di utilizzare il riflesso, è necessario creare dinamicamente un Expression<Func<TSource, TOrder>> e passarlo a OrderBy.

Dai un'occhiata a here per capire come creare una query dinamica.

Problemi correlati