3

I am trying to create a general method for accessing the DB. This will imply parameters like: page index, number of items to display per page, ordering options, load options etc.

...

public IQuerable<T> GetAll(int pageIndex, int itemsToDisplayPerPage, System.Linq.Expressions.Expression<Func<T,object>>[] orderBy, System.Linq.Expressions.Expression<Func<T,object>>[] loadOptions)
{
  DataContext dc = null;
  IQuerable<T> result = null;
  // Make some initalizations
  ...
  foreach(var item in orderBy)
  {
    result = result.OrderBy(item);
  }

  System.Data.Linq.DataLoadOptions loadOptions = new System.Data.Linq.DataLoadOptions();
  foreach(var item in loadOptions)
  {
    loadOptions.LoadWith(item);
  }
  ...
}

...

The problem is that the System.Linq.Expressions.Expression< Func< T,object > > type is not a good general representation of any lambda expression that will be passed for the both examples above.

On ordering will crash because of the object type that does not make any sense for ordering. Also on loadWith will not work. So i dont know how can i handle this problem. Any suggestions? Thank you.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Alex
  • 431
  • 1
  • 6
  • 14
  • result = null; result = result.OrderBy(...); But result is null, what is the OrderBy operating on? – Colin Mackay Dec 08 '11 at 22:40
  • Question: if you want to encapsulate things like ordering, loading, paging, etc, in your method, why does it still return IQueryable? If you're taking care of all of the query options inside of the method, why not enumerate it with .ToList() and return a Collection instead? – danludwig Dec 08 '11 at 23:39

1 Answers1

0

Not sure about the LoadWith, as we are using linq to entities, but we successfully got orderby to work in a repository Get method. The client code looks like this:

var results = _repository.GetAll(
    new GetAllCriteria()
        .OrderBy(x => x.Property1)
        .OrderBy(x => x.Property2)
);

We aren't using generics in repository methods just yet, that will probably come in a future refactor. But the criteria implementation looks like this:

public class GetAllCriteria
{
    public Dictionary<Expression<Func<CustomType, object>>, bool> ToBeOrderedBy 
    { 
        get; private set;
    }

    public GetAllCriteria OrderBy(
        Expression<Func<CustomType, object>> expression)
    {
        return OrderBy(expression, true);
    }

    public GetAllCriteria OrderByDescending(
        Expression<Func<CustomType, object>> expression)
    {
        return OrderBy(expression, false);
    }

    private GetAllCriteria OrderBy(
        Expression<Func<CustomType, object>> expression, bool isAscending)
    {
        if (expression != null)
        {
            if (ToBeOrderedBy == null)
                ToBeOrderedBy = new Dictionary<Expression<Func<CustomType, object>>, bool>();
            ToBeOrderedBy.Add(expression, isAscending);
        }
        return this;
    }   
}

Then, the repository orders like so:

public Collection<CustomType> GetAll(GetAllCriteria criteria)
{
    var query = dbContext.CustomTypes.AsQueryable();

    // some code

    // apply order by
    if (criteria.ToBeOrderedBy != null && criteria.ToBeOrderedBy.Count > 0)
    {
        var firstOrderBy = criteria.ToBeOrderedBy.First();
        query = firstOrderBy.Value
            ? query.OrderBy(firstOrderBy.Key)
            : query.OrderByDescending(firstOrderBy.Key);

        query = criteria.ToBeOrderedBy.Skip(1).Aggregate(query, 
            (lastOrderBy, nextOrderBy) => nextOrderBy.Value
            ? ((IOrderedQueryable<CustomType>)lastOrderBy)
                .ThenBy(nextOrderBy.Key)
            : ((IOrderedQueryable<CustomType>)lastOrderBy)
                .ThenByDescending(nextOrderBy.Key));
    }

    // some more code

    var results = query.ToList();
    return results;
}

If this works with linq to entities, I would imagine it should work with linq to sql.

danludwig
  • 46,965
  • 25
  • 159
  • 237
  • P.S. -- if you are using LoadWith for eager loading, we accomplished this too. Similar to pattern above, except the criteria method is public GetAllCriteria EagerLoad(Expression>) and the ToBeEagerLoaded property is public ReadOnlyCollection>> ToBeEagerLoaded {get { // code } } – danludwig Dec 08 '11 at 23:43
  • Its a nice pattern but it also crashes because of the object type. I receive Cannot order by type 'System.Object'. I need a data type where i can hold the lambda expressions and there pass it to OrderBy function, but this i think is impossible. – Alex Dec 09 '11 at 08:10