开发者

Linq Sort with Text value, not lambda

MVC3 website. EF4.1 Code First.

I am saving the sort column and direction off to session, so that when the user comes back to the page the grid is still in the same sort order.

I want to be able to specify how to sort the collection with the values I have saved like so.

this.Issues = this.db.ITIssues.Orderby(this.sort + " " + this.sortdir)...

Currently I have to use a switch statement and handle every different combination of fields + sort direction. Is there a better way?

switch (this.Sort)
{
    case "ITApplication.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.ITApplication.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "ITIssueType.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.ITIssueType.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.ITIssueType.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CurrentStatus.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentStatus.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentStatus.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CurrentAssignedTo.Fname":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentAssignedTo.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentAssignedTo.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CreatedBy.Fname":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CreatedBy.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CreatedBy.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CurrentPriority.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentPriority.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentPriority.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    default:
 开发者_运维百科       this.Issues = this.db.ITIssues.OrderByDescending(i => i.ID).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;
}


I've had to do something similar recently, what you are looking for is Dynamic Linq! Take a look at this:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx


There seems to be two obstacles with your code, the first involves getting a property name from the string represented by this.Sort. That's probably going to involve some reflection code. The second part involves shortening the amount of code needed to specify ascending sort vs descending sort.

You could do this is several ways. The first idea I thought of was to make an extension method for OrderBy which took in a bool SortDir argument. There are a few overloads for OrderBy allowing for Func<T,TKey> KeySelectors and an IComparer<T>. I'll show you the simple one with just a keySelector, but you may want to implement all of them for a fully generic solution

public static class IEnumerableExtentions
{
    public static IEnumerable<T> OrderBy<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, bool reverse)
    {
        return reverse ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
    }
}

With this in place, you could write your code without all those if's

switch (this.Sort)
{
    case "ITApplication.Name":
        this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name, this.SortDir == "ASC").Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;
    /*...*/
}

As a second solution to determining sort order, you pass in an IComparer which uses SortDir. Here's the IComparer implementation you could use

class ReversableComparer : IComparer<IComparable>
{
    private bool _reverse;

    public ReversableComparer(bool reverse)
    {
        _reverse = reverse;
    }

    public int Compare(IComparable x, IComparable y)
    {
        return _reverse ? y.CompareTo(x) : x.CompareTo(y);
    }
}

Then you could write your code

switch (this.Sort)
{
    case "ITApplication.Name":
        this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name, new ReversableComparer(this.SortDir != "ASC")).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;
    /*...*/
}

That's a bit more code to write, but its there if you need it.

As far as the property name/reflection goes, if you're using Linq as part of Linq to SQL, the dynamic linq link provided by @AlbertVo might be worth a look. If you're working more with Linq to Objects, then instead of i => i.ITApplication.Name try playing with i => i.GetType().GetProperty(this.Sort).GetValue(i, null) Of course you'll need System.Reflection to make that work and it may be slower than your original solution.

I hope some of that helped. Cheers.

EDIT As a summary, these two techniques can be combined. Your final code might look like this:

public static class IEnumerableExtentions
{
    public static IEnumerable<T> OrderBy<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, bool reverse)
    {
        return reverse ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
    }
}

void Main()
{
    this.Issues = this.db.ITIssues
        .OrderBy(i => i.GetType().GetProperty(this.Sort).GetValue(i, null), 
            this.SortDir == "ASC")
        .Where(i => i.ITAppGroupID == this.ITAppGroupID);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜