Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OrderBy with a String keySelector

Tags:

c#

.net

lambda

linq

I have the following function that is extracting me distinct values based on the properties of an object, here Client.

    public List<DistinctValue> GetDistinctValues(string propertyName)
    {
        //how should I specify the keySelector ?
        Func<string, object> keySelector = item => propertyName;

        var list = new List<DistinctValue>();
        var values = this.ObjectContext.Clients.Select(CreateSelectorExpression
                              (propertyName)).Distinct().OrderBy(keySelector);
        int i = 0;
        foreach (var value in values)
        {
            list.Add(new DistinctValue() { ID = i, Value = value });
            i++;
        }

        return list;
    }

    private static Expression<Func<Client, string>> CreateSelectorExpression
                                                        (string propertyName)
    {
        var paramterExpression = Expression.Parameter(typeof(Client));
        return (Expression<Func<Client, string>>)Expression.Lambda(
             Expression.PropertyOrField(paramterExpression, propertyName), 
                                                   paramterExpression);
    }

public class DistinctValue
{
    [Key]
    public int ID { get; set; }
    public string Value { get; set; }
}

I'm doing this because I do not know in before which property values I'll need to extract. It's working, just the result is not sorted.

Can you please help me correct the sorting to make the OrderBy work as expected?

The properties are strings and I don't need to chain the sorting. I don't need to specify the sorting order either.

Thanks a lot in advance, John.

like image 926
Jonx Avatar asked Jan 11 '11 13:01

Jonx


2 Answers

Your keySelector currently returns the same string for each (the property name); and since LINQ is typically a stable sort, this results in no overall change. Since you have already projected to the string values, you can simply use a trivial x=>x mapping here:

var values = this.ObjectContext.Clients.Select(
    CreateSelectorExpression(propertyName)).Distinct().OrderBy(x => x);

to order by the items themselves.

like image 171
Marc Gravell Avatar answered Oct 20 '22 18:10

Marc Gravell


Thanks for the elegant solution. I further expanded upon the CreateSelectorExpression method so it can be leveraged outside of the Client class in the example above.

public static Expression<Func<T, string>> CreateSelectorExpression<T>(string propertyName)
{
    var paramterExpression = Expression.Parameter(typeof(T));
        return (Expression<Func<T, string>>)Expression.Lambda(Expression.PropertyOrField(paramterExpression, propertyName),
                                                                paramterExpression);
}     

Usage

Func<IQueryable<YourEntity>, IOrderedQueryable<YourEntity>> orderBy = o => o.OrderByDescending(CreateSelectorExpression<YourEntity>("Entity Property Name"));
like image 20
Christopher Felpel Avatar answered Oct 20 '22 16:10

Christopher Felpel