2010-06-25 61 views
1

我想做一个存储库类有一个方法来订购基于“排序”参数的结果。我需要将它作为参数传递,因为我试图对我的存储库不返回IQueryable并仅返回List非常严格。问题是我不知道如何使它符合以下要求:存储库与OrderBy

  1. 允许多列。
  2. 强类型到返回的实体(列没有字符串作为参数)。
  3. 能够按降序设置特定列。

这是甚至可能或无用的,一个存储库允许返回与排序?版本库是否应该能够执行CRUD操作?也许返回IQueryable将是最好的选择?

+0

'我想是非常严格的,我的仓库不返回IQueryable的,只有返回List.' - 不要这样做。 IQueryable/IEnumerable是你的朋友。 (请查看http://google.com/search?q=deferred+execution) – Omar 2010-06-25 16:35:56

回答

6

也许你需要的东西是这样的:

public class Ordering<T> 
{ 
    private readonly Func<IQueryable<T>, IOrderedQueryable<T>> transform; 

    private Ordering(Func<IQueryable<T>, IOrderedQueryable<T>> transform) 
    { 
     this.transform = transform; 
    } 

    public static Ordering<T> Create<TKey> 
     (Expression<Func<T, TKey>> primary) 
    { 
     return new Ordering<T>(query => query.OrderBy(primary)); 
    } 

    public Ordering<T> ThenBy<TKey>(Expression<Func<T, TKey>> secondary) 
    { 
     return new Ordering<T>(query => transform(query).ThenBy(secondary)); 
    } 

    // And more for the descending methods... 

    internal IOrderedQueryable<T> Apply(IQueryable<T> query) 
    { 
     return transform(query); 
    } 
} 

然后客户可以创建一个Ordering<T>传递到存储库,并repositry可以调用ApplyIQueryable<T>。那有意义吗?

样品(略带傻气)使用方法:

var ordering = Ordering<FileInfo>.Create(fi => fi.Length) 
           .ThenBy(fi => fi.Name); 
+0

是的,这正是我正在寻找的。如何使用此不必从 'repository.GetOrderedBy(订购 .Create <的EntityType,int>的(E => e.Column))' 使用类型推断供应类型: 'repository.GetOrderedBy (Ordering.Create(e => e.Column))' 或者这是不可能的,因为'Ordering.Create'是静态的? – TheCloudlessSky 2010-06-25 16:27:42

+0

@TheCloudlessSky:哎呀,这是一个错字。 Create方法应该只声明一个类型参数。 – 2010-06-25 16:37:22

+0

感谢乔恩,现在有道理。你认为这样做是否过分矫枉过正?你认为最好是返回'IQueryable'并在存储库之外进行排序吗? – TheCloudlessSky 2010-06-25 16:42:37

3

这是有争议的,但我认为你的仓库应该只是返回数据。让你的消费类担心集合的排序。

这背后的思考过程非常简单,消费类无论如何决定订单。所以他们可以通过它在你的仓库中手工制作orderby生成器,并让它完成工作,或者他们可以使用linq并且命令他们从仓库获得的集合。我认为后者更容易实现,不太容易出错,并且在阅读代码时会更有意义,但我认为我的观点再次是有争议的。

+0

如果没有争议,我大部分时间都同意你的观点,但有几次可以让储存库处理订购。例如,当实际的数据存储可以比代码更高效地排序时,或者如果您需要卸载处理以保持当前系统响应。 – 2010-06-25 16:10:19

+0

我同意你的意见。但是不应该在存储库中执行所有的SQL(也就是.ToList())执行,而不是继续前进? – TheCloudlessSky 2010-06-25 16:10:40

+0

@TheCloudlessSky:为什么?这就是IQueryable的要点 - 您允许将数据执行推迟到真正需要时,这意味着您可以防止不必要的复杂查询对数据库执行。让你的仓库做ToList()只是意味着你将更多的负担放在你的DB上...... – 2010-06-25 16:18:03

2

我认为直接返回IQueryable<T>通常是最好的选择。

例如,假设您有一个方法查询数据库以返回特定的表或视图。如果您的存储库的客户端只需要前10条记录,并使用自定义条件以及您没有预料到的排序,则可以通过返回IQueryable<T>来允许这样做。客户端只需要添加.Where(...).OrderBy(...).Take(10);

随着IQueryable<T>,数据层上的调用将自动适应,并且只拉动10条记录。如果您返回一个List,则您的数据库查询将提取每条记录,然后过滤将需要在您的应用程序中发生。

这增加了巨大的处理/网络/等开销,没有真正的原因。

+0

这是我的这个困境。从我读过的,最好*不*返回'IQueryable '的存储库。 – TheCloudlessSky 2010-06-25 16:12:46

+0

@ TheCloudlessSky:我不知道你在哪里阅读过,但我认为这是一个不好的建议......除非有某些具体的理由来阻止这一点。 – 2010-06-25 16:18:23

+0

首先想到的是,您正在使用这种技术将实际的数据访问从存储库移动到任意位置。它确实解决了列出的问题。 – 2010-06-25 16:20:07