Linq 使用文本值排序,而不是 lambda



MVC3 网站。EF4.1 代码优先。

我将排序列和方向保存到会话,以便当用户返回页面时,网格仍保持相同的排序顺序。

我希望能够指定如何使用我保存的值对集合进行排序。

这。问题 = this.db.ITIssues.Orderby(this.sort + " " + this.sortdir)...

目前,我必须使用 switch 语句并处理字段 + 排序方向的每个不同组合。有没有更好的方法?

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;
}

我最近不得不做类似的事情,你正在寻找的是动态 Linq!看看这个:

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

您的代码似乎有两个障碍,第一个涉及从 this.Sort 表示的字符串中获取属性名称。 这可能涉及一些反射代码。 第二部分涉及缩短指定升序排序与降序排序所需的代码量。

您可以通过多种方式做到这一点。 我想到的第一个想法是为 OrderBy 创建一个扩展方法,该方法采用布尔值 SortDir 参数。 OrderBy 有一些重载允许Func<T,TKey>键选择器和IComparer<T>。 我将向您展示仅使用keySelector的简单方法,但是您可能希望实现所有这些解决方案以获得完全通用的解决方案

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);
    }
}

有了这个,你可以在没有所有这些if的情况下编写代码。

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;
    /*...*/
}

作为确定排序顺序的第二种解决方案,您传入一个使用 SortDir 的IComparer。 这是您可以使用的 IComparer 实现

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);
    }
}

然后你可以编写你的代码

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;
    /*...*/
}

这需要编写更多的代码,但如果您需要它,它就在那里。

就属性名称/反射而言,如果您使用 Linq 作为 Linq to SQL 的一部分,则 @AlbertVo 提供的动态 linq 链接可能值得一看。 如果您更多地使用 Linq to Objects,那么与其尝试使用 i => i.ITApplication.Name i => i.GetType().GetProperty(this.Sort).GetValue(i, null)当然,您需要System.Reflection才能完成这项工作,并且它可能比原始解决方案慢。

我希望其中一些有所帮助。 干杯。

编辑总而言之,这两种技术可以结合起来。 最终代码可能如下所示:

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);
}

相关内容

  • 没有找到相关文章

最新更新