Question

I'm looking for a solution to store a variety ofExpression<Func<T, TProperty>> used to organize the components before running the stored list against aIQueryable<T> object (the underlying provider is Entity Framework).

For instance, I'd want to carry out the following (This is a fake language):

public class Program
{
    public static void Main(string[] args)
    {
        OrderClause<User> orderBys = new OrderClause<User>();
        orderBys.AddOrderBy(u => u.Firstname);
        orderBys.AddOrderBy(u => u.Lastname);
        orderBys.AddOrderBy(u => u.Age);

        Repository<User> userRepository = new Repository<User>();
        IEnumerable<User> result = userRepository.Query(orderBys.OrderByClauses);
    }
}

The following is an order by clause (item to order):

public class OrderClause<T>
{
    public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
    {
        _list.Add(orderBySelector);
    }

    public IEnumerable<Expression<Func<T, ???>>> OrderByClauses
    {
        get { return _list; }
    }
}

A repository that uses my search technique

public class Repository<T>
{
    public IEnumerable<T> Query(IEnumerable<OrderClause<T>> clauses)
    {
        foreach (OrderClause<T, ???> clause in clauses)
        {
            _query = _query.OrderBy(clause);
        }

        return _query.ToList();
    }
}

My first thought was to convert theExpression<Func<T, TProperty>> into a chain (the property name on which to sort). In essence, I keep a list of strings with the attributes to sort on rather than a typed list (which is not feasible since the TProperty is not constant).

However, this is ineffective since I am unable to reassemble theExpression (I need it since IQueryable.) back OrderBy performs aExpression<Func<T, TKey>> as a variable).

Additionally, I attempted to dynamically construct the Expression (using Expression.Convert) in order to have aExpression<Func<T, object>> However, entity framework then threw an error, stating that it couldn't handle the Expression. Statement converting.

I prefer not to utilize a third-party library like the Dynamic Library for Linq.

1
11
10/28/2013 10:11:56 PM

Accepted Answer

One of the rare instances when adynamic The / reflection solution could be suitable.

I believe you want something similar. (I've interpreted what you said and changed your structure where I felt it was essential.)

public class OrderClauseList<T>
{
    private readonly List<LambdaExpression> _list = new List<LambdaExpression>();

    public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
    {
        _list.Add(orderBySelector);
    }

    public IEnumerable<LambdaExpression> OrderByClauses
    {
        get { return _list; }
    }
}

public class Repository<T>
{
    private IQueryable<T> _source = ... // Don't know how this works

    public IEnumerable<T> Query(OrderClause<T> clauseList)
    {
        // Needs validation, e.g. null-reference or empty clause-list. 

        var clauses = clauseList.OrderByClauses;

        IOrderedQueryable<T> result = Queryable.OrderBy(_source, 
                                                        (dynamic)clauses.First());

        foreach (var clause in clauses.Skip(1))
        {
            result = Queryable.ThenBy(result, (dynamic)clause);
        }

        return result.ToList();
    }
}

The main tip is to learn C#.dynamic to do the dreadful type-inference and overload resolution for us. Additionally, I think that the above, notwithstanding the usage ofdynamic , is really safe to type!

10
5/22/2013 2:17:32 PM

Popular Answer

To do this, one method would be to "oestore" all the sort clauses in something likeFunc<IQueryable<T>, IOrderedQueryable<T>> (i.e., a function that utilizes the sorting techniques):

public class OrderClause<T>
{
    private Func<IQueryable<T>, IOrderedQueryable<T>> m_orderingFunction;

    public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
    {
        if (m_orderingFunction == null)
        {
            m_orderingFunction = q => q.OrderBy(orderBySelector);
        }
        else
        {
            // required so that m_orderingFunction doesn't reference itself
            var orderingFunction = m_orderingFunction;
            m_orderingFunction = q => orderingFunction(q).ThenBy(orderBySelector);
        }
    }

    public IQueryable<T> Order(IQueryable<T> source)
    {
        if (m_orderingFunction == null)
            return source;

        return m_orderingFunction(source);
    }
}

You avoid having to cope with introspection ordynamic All of this code is type safe and rather simple to comprehend.



Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow