c# - Como usar uma string para criar uma ordem EF por expressão?



entity-framework linq (1)

Criar uma expressão não é difícil, mas a parte complicada é como vinculá-la aos métodos OrderBy(Descending) / ThenBy(Descendig) quando você não conhece o tipo da propriedade (daí o tipo do resultado da expressão do seletor) .

Aqui está tudo o que está encapsulado em um método de extensão personalizado:

public static partial class QueryableExtensions
{
    public static IOrderedQueryable<T> OrderByMember<T>(this IQueryable<T> source, string memberPath)
    {
        return source.OrderByMemberUsing(memberPath, "OrderBy");
    }
    public static IOrderedQueryable<T> OrderByMemberDescending<T>(this IQueryable<T> source, string memberPath)
    {
        return source.OrderByMemberUsing(memberPath, "OrderByDescending");
    }
    public static IOrderedQueryable<T> ThenByMember<T>(this IOrderedQueryable<T> source, string memberPath)
    {
        return source.OrderByMemberUsing(memberPath, "ThenBy");
    }
    public static IOrderedQueryable<T> ThenByMemberDescending<T>(this IOrderedQueryable<T> source, string memberPath)
    {
        return source.OrderByMemberUsing(memberPath, "ThenByDescending");
    }
    private static IOrderedQueryable<T> OrderByMemberUsing<T>(this IQueryable<T> source, string memberPath, string method)
    {
        var parameter = Expression.Parameter(typeof(T), "item");
        var member = memberPath.Split('.')
            .Aggregate((Expression)parameter, Expression.PropertyOrField);
        var keySelector = Expression.Lambda(member, parameter);
        var methodCall = Expression.Call(
            typeof(Queryable), method, new[] { parameter.Type, member.Type },
            source.Expression, Expression.Quote(keySelector));
        return (IOrderedQueryable<T>)source.Provider.CreateQuery(methodCall);
    }

Estou tentando obter essa conversão

"Address.Street" => (p) => p.Address.Street
"Name" => (p) => p.Name

Consegui encontrar um método para gerar um pedido por expressão usando reflexão, mas ele não funcionará para classificação complexa como Address.Street pois funciona para um único nível de propriedade.

Existe uma maneira de fazer isso? Vi que compilei expressões lambda, mas não conseguia entender como fazê-lo funcionar neste caso.





linq