views:

453

answers:

4

This is my query, how can I use string as orderby parameter?

string sortColumn="Title";

var  items = (from ltem in ctxModel.Items
              where ltem.ItemID == vId
              orderby //something here
              select ltem).Skip(PageSize * PageIndex).Take(PageSize);

UPDATE:
I can't just OrderBy the result set, because I FIRST need to sort, and only THEN to page.

+2  A: 

That query looks like you're using custom databinding and/or ObjectDataSource, regardless, there is a way to do this using an extension method which takes a sort expression and dynamically appends an OrderBy() call (expression) to the linq query. I documented how in blog post a while back, which coincidentally was part of this SO question. If you need more than that, you could use dynamic linq which is documented pretty well by scottgu.

EDIT: using the extension method would make it look like

string sortColumn="Title";

    var  items = (from ltem in ctxModel.Items
                  where ltem.ItemID == vId
                  select ltem).Skip(PageSize * PageIndex).Take(PageSize).OrderBy(sortColumn);
ray2k
Dynamic Linq FTW
Sky Sanders
The problem is that I need first to sort and only then to page
verror
@verror this is not a problem. follow the links
Sky Sanders
If it's a linq query, internally it's just an expression tree. There is no difference between (query).Skip(5).Take(5).OrderBy(p => p.Title); and (query).OrderyBy(p => p.Title).Skip(5).Take(5)But you can call it first if you prefer.
ray2k
in your example (the one in the answer), OrderBy can't receive strings because the return type of the query is IQueryable
verror
Maybe you should follow some of the links then. That 'blog post' link has code for an OrderBy(string) extension method, and the 'dynamic linq' has much more if you need more than just sorting by strings.
ray2k
A: 

Others have suggested using Dynamic link or other libraries. Personally, I would not bring in a library dependency for such a small task. But two other paths that you can take are...

  • Use Object Call syntax and build your query expression tree dynamically. For example...

See http://blog.cincura.net/229310-sorting-in-iqueryable-using-string-as-column-name/

It is important to consider Deferred Execution in this scenario. You can safely build your query that returns an IQueryable object and then run a object query sort on that object. Your query will only be run once, when the data is actually accessed.

The above blog post is an example of how you can use the Expression API to build and expression tree that you can use for your OrderBy. It really just sounds complicated. The MSDN article may be a better reference. See How to: Use Expression Trees to Build Dynamic Queries on MSDN.

Or

  • Use the simple route and just use a switch on the title for the entire query.

Eg.

ItemType items = default(ItemType);
switch(sortColumn)
{
     case "Title":
     {
           items = ctxModel.Items
                    .Where(i => i.ItemID == vId)
                    .OrderBy( i => i.Title);
     }
     break;
 }
kervin
downvote trigger finger twitching, must resist. This is, IMO, the antithesis of dynamic. wait, it will come to me... oh yeah, this is hardcoded X 2. ;-)
Sky Sanders
This will require me to make similar cases for all columns, i have 8 of them.
verror
@Sky. What are you talking about?
kervin
@verror: There are two solutions in my answer. You can (a) Build an expression for your OrderBy dynamically ( see link ), or (b) Use a switch on the column title. I guess "b" doesn't work for you so I don't see another option besides building the expression.
kervin
using your (a) I should pass my full result set (without paging) through this sorting function and then I should page it as planned? (I need first to sort and then to page)
verror
@verror: I've modified my answer with more information, including another article that may help. It's not a result set perse, but more like modifying the expression tree, *before* the result set is returned. Remember that your IQueryable object does not have data yet.
kervin
+2  A: 

Here's another alternative, the EntitySorter. Allows a bit what dynamic LINQ does with strings, but wraps the operation in a object, just like with the Query Object pattern. It allows both sorting by strings, and by type safe constructs. Here are some examples:

// Ways of defining an entity sorter
// 1. Using strings:
IEntitySorter<Person> sorter = EntitySorter<Person>
    .OrderBy("Address.City")
    .ThenByDescending("Id");

// 2. Defining a sorter with lambda's
IEntitySorter<Person> sorter = EntitySorter<Person>
    .OrderByDescending(p => p.Name)
    .ThenBy(p => p.Id)
    .ThenByDescending(p => p.Address.City);

// 3. Using a LINQ query
IEntitySorter<Person> sorter =
    from person in EntitySorter<Person>.AsQueryable()
    orderby person.Name descending, person.Address.City
    select person;

// And you can pass a sorter from your presentation layer
// to your business layer, and you business layer may look
// like this:
static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
    using (var db = ContextFactory.CreateContext())
    {
        IOrderedQueryable<Person> sortedList =
            sorter.Sort(db.Persons);

        return sortedList.ToArray();
    }
}

You can find the code here.

Steven
A library just for dynamic sort by one column is to much for my case...
verror
Then go for kervin's answer ;-)
Steven
@Verror: The EntitySorter<T> is not a library btw. The implementation consists of 180 LoC and can be copy-pasted into your own project. You can copy-paste it all in once from here: http://servicelayerhelpers.codeplex.com/SourceControl/changeset/view/34401#537056
Steven
+1  A: 

Apparently the other allusions to Dynamic Linq are not clear enough. Let me shed some light..

Using Dynamic Linq does not necessarily indicate the need for an assembly dependency.

Dynamic Linq is contained in one source file, if I am not mistaken, that is included in the C# samples everyone should have at least looked at sometime in the last 3 years, and can easily be dropped into a project and namespaced to prevent collisions, thus providing expression building services that can be utilized wherever this need arises.

I consider the ability to safely construct an expression from a reasonably arbitrary string, which can easily be built on the fly to be the best example of 'dynamic'.

Consider:

    var query = northwind.Products
                         .Where("CategoryID = 3 AND UnitPrice > 3")
                         .OrderBy("SupplierID");
Sky Sanders
+1, for no hard feelings. Sky, you should not downvote answers simply because you disagree with them. The dynamic Linq library in the background does exactly what I suggested in the first part of my answer. It builds the criteria expression tree at runtime. MSDN reference also explains the process. The programmer can decide whether he would like to introduce a dependency for that feature or code it himself.
kervin
@kervin - did I downvote? In any case, I updated my answer with a clarification of my predisposition towards Dynamic Linq in this case.
Sky Sanders