【问题标题】:Generic Repository Extending: Inheritance vs. Extension Methods通用存储库扩展:继承与扩展方法
【发布时间】:2014-02-15 15:12:46
【问题描述】:

我计划在我的实体框架项目中使用通用存储库。但是对于基本通用存储库不包含的操作,哪个更好地扩展存储库。

继承:

public class CustomerRepository:Repository<Customer>
{
    public decimal GetCustomerOrderTotalByYear(int customerId, int year)
    {
        return base
            .FindById(customerId)
            .Orders.SelectMany(o => o.OrderDetails)
            .Select(o => o.Quantity*o.UnitPrice).Sum();
    }
}

扩展方法:

public static class CustomerRepositoryExtensions
{
    public static decimal GetCustomerOrderTotalByYear(this Repository<Customer> customerRepository, int customerId, int year)
    {
        return customerRepository
            .FindById(customerId)
            .Orders.SelectMany(o => o.OrderDetails)
            .Select(o => o.Quantity*o.UnitPrice).Sum();
    }
}

【问题讨论】:

  • 我赞成继承方法,因为查询特定于 CustomerRepository 类。一个问题。为什么 CustomerRepository 类是静态的?
  • 又是扩展风格;它也特定于 Repository。而且我把第一堂课的static去掉了,写错了。
  • 扩展方法的问题是,您需要在计划使用扩展方法的任何地方包含命名空间。使用继承方法,您可以使用存储库对象免费访问该方法。
  • 当通用实现也无法满足您的所有需求时,创建一个具体的存储库是完全可以的。但是,我会使用扩展方法的唯一时间是当您无法控制“服务”的实现时。目前,我完全有这种情况——提供的版本具有抽象属性,我无法看到“幕后”(还)。所以,是的……去做吧。

标签: c# entity-framework inheritance extension-methods repository-pattern


【解决方案1】:

旧帖子,但是当我发现扩展更合适时,我想补充一点 - 当您通过 DI 容器解决依赖关系并且您拥有 很多 Repositories 时。在这种情况下,您只需要注册您的通用仓库,而不是单独注册一个。

【讨论】:

    【解决方案2】:

    不要在存储库上创建查询方法。使用存储库来维护聚合一致性,而不是用于通用查询。否则,您的界面会非常臃肿,并且您的存储库最终会成为无数不同查询的垃圾场。只需创建查询和查询处理程序。我只使用存储库来获取我要更新的数据。

    执行this 之类的操作。

    这是一种更加SOLID 的方法。

    【讨论】:

    • 附录:查询处理程序不能替代存储库,处理程序可以使用存储库。虽然在 DDD 中,存储库仅用于域目的,但存储库模式与 DDD 无关,它可以在域外以相同的目的使用:抽象持久性并将应用程序对象与其持久性形式解耦。就个人而言,我的查询处理程序使用专门的查询存储库(当然是接口),因为我不希望我的 DAL 知道我的视图模型。在我的例子中,查询处理程序充当持久性和视图模型之间的桥梁。
    • 同意。然而,大多数人都在使用 ORM 并通过存储库来调整查询的性能,而不仅仅是在接口上有很多方法(这从来都不是很好)。每个查询都需要正确的包含、投影等。对于我做过的大多数系统,我直接查询 ORM。我倾向于发现我查询 ORM 转换然后通过 Automapper 在查询中转换为视图模型。然后,如果您需要更多性能非规范化为快速存储并让您的查询只返回持久视图模型。如果您有查询和处理程序 - 您已经有一个隐藏数据层的抽象。它的所有权衡虽然:)
    【解决方案3】:

    我通常走的是继承路线。这看起来与您发布的内容非常相似。我有一个注入 IUnitOfWork 的通用“基础”存储库实现。然后在我的每个 BaseRepository 继承类中,我将实现我的查询。这是我使用此“模式”的旧版本制作的旧帖子:https://stackoverflow.com/a/18788895/1426342

    这种方法对我来说似乎总是最直接的,并且在我交付代码时更容易向我的客户解释。从前到后遵循执行路径更容易。但是,对于较大的系统,它会变得非常混乱!它还将您的上下文实现耦合到您的存储库。从那以后,我做了一些额外的操作,将上下文类型作为泛型传递,这有助于实现这一点,并允许我拥有多个上下文实现,如果你愿意,我可以发布。

    然而,最近,一位同事要求我进一步分解它并将实体框架与我的存储库实现分离,我尝试了您发布的第二种方法。老实说,我想我可能更喜欢这种方法。对我来说它似乎更轻量级,因为您没有注入所有那些实际上甚至不需要注入的不同“存储库”方法。看看这个家伙的博客,看看这个实现的一个很好的例子:http://blog.longle.net/2013/05/11/genericizing-the-unit-of-work-pattern-repository-pattern-with-entity-framework-in-mvc

    在仔细研究之后,我想你会同意的。扩展方法是一种性能更高的解决方案。

    【讨论】:

      【解决方案4】:

      我会选择继承。

      在我看来,扩展方法是合适的,当你想为你无法控制的类添加功能时(例如字符串扩展),或者当你想为一个无论如何都应该做同样事情的接口提供功能时您当前正在使用哪个实现(例如 LINQ 是 IEnumerable 的一组扩展)

      在这种情况下,说“这是我的 CustomerRepository,CustomerRepository 有一些额外的东西或做一些与默认行为略有不同的东西,但最终是一个客户存储库 一个存储库。

      请注意,这都是相当主观的,并且基于个人喜好,但我的投票倾向于继承路线。

      【讨论】:

        猜你喜欢
        • 2010-11-11
        • 1970-01-01
        • 1970-01-01
        • 2017-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-07
        • 1970-01-01
        相关资源
        最近更新 更多