views:

42

answers:

1

Now this is a trick question because you cannot do this:

var a = myDB.Where(p => p.field == "filter").OrderBy("it." + fieldname);

You could change the Where to accept a string, which allows you to change the OrderBy to accept a string, but that's not the question.

How can you turn a string like "productID, productName" in to an OrderBy expression? If I am correct in thinking, maybe the question could be "how to turn a Specification Pattern in to an Expression delegate?"

The problem is I don't know what table they want, and thus I don't know the primary key. I used generics to represent the type of table.

public interface IRepository<E, C> where C : ObjectContext  // E is an Entity
{
  void Add(E entity);
  void Del(E entity);
  IList<E> Get(Expression<Func<E, bool>> filterLambda = null,   //Where clause
              Expression<Func<E, object>> orderbyLambda = null, //OrderBy
              int? page = null,                                 //Page to get
              int? pageSize = null,                             //Page Size
              Expression<Func<E, object>> selectLambda = null); //Populate Fields
  int Count(Expression<Func<E, bool>> filterLambda = null);
  bool SaveChanges();
}

The actual statement I use to pull content from the data context (data container?) is

this.GetEntity().Where(filterLambda)
                .OrderBy(orderbyLambda)
                .Skip(((int)page - 1) * (int)pageSize)
                .Take((int)pageSize)
                .Select(selectLambda).ToList();

I need the OrderBy() to implement .Skip() and .Take(). For all those of you who think you can do this are correct for Linq to SQL. However, Linq to Entities does not support it:

The method 'Skip' is only supported for sorted input in LINQ to Entities.
The method 'OrderBy' must be called before the method 'Skip'.
+1  A: 

You don't have to build the query in a single statement. As the query is not executed until you do the ToList at the end, you can use conditions to build it. Example:

var query = myDB.Where(p => p.field == "filter");

string sort = "productID, productName";

string[] sortItems = sort.Split(new string[] {", "}, StringSplitOptions.None);
switch (sortItems[0]) {
  case "productId": query = query.OrderBy(x => x.ProductId); break;
  case "productName": query = query.OrderBy(x => x.ProductName); break;
}
for (int i = 1; i < sortItems.Length; i++) {
  switch (sortItems[i]) {
    case "productId": query = query.ThenBy(x => x.ProductId); break;
    case "productName": query = query.ThenBy(x => x.ProductName); break;
  }
}
query = query.Skip(10).Take(10);

(However, the type of the query object may change when you add sorting (e.g. from IEnumerable<T> to IOrderedEnumerable<T>), so you might need some more variables to store the different stages.)

Guffa
That's an extremely creative and effective answer. I wonder if there's a way to turn the "productid" in to x => x.ProductId. I won't know the fields ahead of time, so I couldn'
Dr. Zim
Let's try that comment again: That's an extremely creative and effective answer. I wonder if there's a way to turn the "productid" in to x => x.ProductId. I won't know the fields ahead of time, however that doesn't belittle that this answer could definitely work. I will give it a try. Thank you.
Dr. Zim
@Dr. Zim: That should be possible by using reflection to get a `PropertyInfo` for the property, and dynamically creating an expression from that.
Guffa
Just drawing a blank on how you could convert the string values back in to a real object, namely the field I need to order by.
Dr. Zim
Expando Object comes to mind, but it may not be the right data type.
Dr. Zim
@Dr. Zim: Getting the property value from the string is fairly easy, but that doesn't translate into SQL. You need to create an expression object that LINQ to SQL can translate into SQL. Perhaps something like this: http://stackoverflow.com/questions/3112309/dynamic-query-using-expression-tree
Guffa