2011-05-13 73 views
1

MVC3网站。 EF4.1 Code First。Linq排序文本值,而不是lambda

我保存关闭会话排序列和方向,这样当用户回到页面电网仍处于相同的排序顺序。

我希望能够指定如何与我救了,像这样的数值集合进行排序。

this.Issues = 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; 
} 

回答

0

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

你可以做到这一点的几种方法。我想到的第一个想法是为OrderBy创建一个扩展方法,它接受了一个bool SortDir参数。 OrderBy有几个重载允许Func<T,TKey> KeySelectors和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); 
    } 
} 

有了这个所有的人,你可以写你的代码,而所有这些,如果是

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为SQL的LINQ的一部分,由@AlbertVo提供的动态链接LINQ可能是值得一试。如果你正在使用LINQ的工作更多的对象,然后代替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); 
} 
+0

马丁,感谢您的伟大建议和代码。我发现很难相信每个人都在使用switch语句来订购他们的动态排序顺序。似乎......我不太了解linq如何在引擎盖下工作,写出“似乎”。我会等待更多的评论,如果没有更多的评论,我会将其标记为答案。谢谢你。 – Terrence 2011-05-13 18:13:34

+0

@TPSpencer我也注意到,在所有情况下,.Where(...)部分都是一样的。因为Linq是可组合的,所以你可以将所有的.Where子句从你给出的代码片段中删除,并在切换后放置一个额外的任务。就像'this.Issues = this.Issues.Where(...)'这样的东西' – 2011-05-13 19:10:19

+0

好点Martin,谢谢你指出。你最终的代码编辑看起来很有前途。 – Terrence 2011-05-13 21:26:37