通用仓储库。需要建议。

4
我在思考该选择哪种方式,无法决定哪一种更好。也许你可以给我一个杀手级的想法 :)
我的问题是:我有一个建立在NHibernate之上的通用仓库。它的接口非常简单,例如Get(object id),Save,Delete等。有时这个接口运行良好,但有时却不行。例如,我的项目中有几个实体具有名为Code的属性(但并非全部)。我希望能够通过主键以及此属性获取实体。另一个情况是当我需要过滤某些具有日期或提供其他特定于各个实体的筛选条件的实体时。目前我正在考虑以下解决方案:
  • Linq - 我可以从每种类型的Repository返回一个IQueryable对象,然后使用linq表达式过滤查询。我不喜欢这个想法,因为如果我走这条路,我看不到Repository背后的原因。
  • 特定于实体的存储库 - 在这里,我可以在通用存储库之上构建一个特定于实体的存储库。它将具有诸如Get(DateTime dateFrom, DateTime dateTo)等方法。缺点是我必须为每个实体对象创建一个存储库类。好处是它将更容易地将对象图持久化/删除到数据库中,因为它知道实体的依赖关系。
  • 请告诉我 :)
5个回答

3

假设您已经拥有一个通用的仓储接口,我建议使用实体特定的仓储,但是通过扩展您的通用仓储来实现它。这样可以使代码更易于发现,并允许您继续遵循您的仓储模式。这将允许您添加按代码获取和按日期范围传递获取的方法。


谢谢Joel,你的回答也很有帮助,所以我点赞了。另外,就我的情况而言,我更喜欢使用组合。+1 - Davita
谢谢!您仍然可以扩展接口,但是通过在实体特定存储库的实现中利用通用存储库来使用组合(类似于链接问题中选择的答案)。 - Joel Briggs

3

现在是37岁;)有趣的是,最近我正在研究这个。我想使用传统模式来看看这种方法如何工作,而使用存储库会引发各种问题,我的问题几乎总是“我始终可以想到一个特定的情况,我无法支持通用方法。最终,我选择了私人通用存储库和公共特定域存储库,以强制执行域关系规则。当我使用nHibernate时,我仍然有一些需要解决的问题,但没有致命问题。 - Ian
阅读了您的答案(创建通用存储库与为每个对象创建特定存储库的优劣势?)后,现在我清楚了应该选择哪种方法以及原因。谢谢Bryan :) - Davita

2
我主张使用聚合仓库而不是特定实体的仓库。例如,如果您有实体
Project
ProjectStatus
ProjectType

将这三个单独的数据访问库合并为一个单一的存储库是有意义的,而不是分开处理。


谢谢Jamie,我也得出了这个结论。+1 :) - Davita

0

我使用类似这样的东西:注意,它是为Entity Framework设计的,但我想这个模型/设计可以在任何地方使用。

public interface IRepository<T>
{
    T Save(T entity);
    void Delete(T entity);
    IQueryable<T> GetAll();
    T GetById(int id);
}

我从一些关于是否使用IQueryable的问题中得到了这个想法,整个优点在于,你可以轻松地模拟IRepository。
详细信息请参见此答案

是的,那是我现在所拥有的,我在想是否有更好的解决方案,而不是直接使用IQueryable。 - Davita
@Davita 噢,就像我说的,我是基于 Stack Overflow 上的许多问题来学习的,可以看看我链接的答案。我在那里提到了两篇这样的文章。烦人的部分是对于 20 个实体,我有 20 个单独的 IRepos,但是我可以使用 Moq 很好地模拟它们。 - gideon
一些注释:GetById 应该改为 T GetById。我有时使用 IRepository<T, K> 模式,其中 K 是主键的类型。而且,我没有 GetAll 方法,我实际上是让 IRepository<T> 扩展 IQueryable<T>...即仓储本身是可查询的。 - Rich
@rich 谢谢!已经更正。请参考以下链接扩展 IQ<T>..那么你会如何模拟你的 repo 呢?https://dev59.com/qHVC5IYBdhLWcg3w2lCI - gideon

0

您可以使用命名查询来根据非键列获取行,或者使用Hibernate查询语言(hql)进行任何类型的过滤,它与SQL语句非常相似。

这可能会有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接