【问题标题】:Repository pattern: One repository class for each entity?存储库模式:每个实体一个存储库类?
【发布时间】:2010-08-19 17:48:46
【问题描述】:

假设您在 LINQ 类中定义了以下实体:

Product
Customer
Category

我是否应该为所有人提供一个存储库类:

StoreRepository

...或者我应该有:

ProductRepository
CustomerRepository
CategoryRepository

各有什么优缺点?就我而言,我的解决方案中有几个“应用程序”...... Store 应用程序只是其中之一。

【问题讨论】:

    标签: asp.net-mvc linq linq-to-sql repository-pattern


    【解决方案1】:

    这是我的观点。我是存储库模式的严格追随者。应该有 3 种方法采用单个实体。添加、更新、删除,一般定义。

    public interface IRepository<T>
    {
         void Add(T entity);
         void Update(T entity);
         void Delete(T entity);
    }
    

    除了这些方法之外,您还要处理“查询”或服务方法。如果我是你,我会按照上面一般定义的存储库,添加一个如下所示的“QueryProvider”,然后将您的业务逻辑它所属的位置放在“服务”或“命令/查询”(来自 CQRS,谷歌)

    public interface IQueryProvider<T>
    {
         TResult Query<TResult>(Func<IQueryable<T>, TResult> query);
    }
    

    (希望我的意见有点用:))

    【讨论】:

    • 这真的很有趣,谢谢你的提示。
    • Get() 实体呢?那会在存储库中的什么位置?
    • 在此之后,Get() 将是一个具有单个结果的查询。
    • @Necros,我同意。这甚至可以使用扩展方法来实现,如果你这样做的话。
    • @zowens 我个人喜欢我的存储库更丰富一点。我这样滚动:github.com/Necroskillz/NecroNetToolkit/tree/master/Source/…
    【解决方案2】:

    这一切都取决于您将如何成为“领域驱动设计”。你知道什么是聚合根吗?大多数情况下,一般输入的 with 可以完成所有基本的 CRUD 就足够了。只有当您开始拥有具有上下文和边界的厚模型时,这才开始变得重要。

    【讨论】:

    • 我必须查一下,但我想我明白了......所以我的产品将是一个聚合,因为它封装了类别。即使我的客户对象“有很多”产品,它也是一个单独的“想法”,因此是一个单独的聚合。这听起来正确吗?您是否建议为每个聚合根创建一个类?
    • 哇,哇,哇,慢点。因此,如果您在不完全了解 DDD 的情况下尝试实施 DDD,您将变得非常沮丧并且您的质量将受到影响。现在保持简单,只需为每个实体实现一个存储库。
    【解决方案3】:

    基本上每个聚合根对象都会有一个存储库。在ASP.NET MVC 2 in Action这本书中有一些关于DDD和聚合根对象以及我们应该如何设计存储库类的有趣观点,如果您想了解更多信息,请查看。

    【讨论】:

      【解决方案4】:

      我有一个存储库/对象,因为总是需要从我的 EntityTable 到我的域对象的映射(例如在 GetIQueryableCollection() 的主体中。我是如何绕过编写这个重复代码的通过制作 T4 模板为我生成它。

      我有一个示例项目,它在 codeplex http://t4tarantino.codeplex.com/ T4 Toolbox 业务类和存储库示例模板上生成存储库模式。 如果不进行一些调整,它可能无法完全按照您想要的方式工作,除非您已经实现了 Tarintino 和其他一些好东西,但是模板很容易配置。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using Cses.Core.Domain.Model;
      using StructureMap;
      
      namespace Cses.Core.Domain
      {
          /// <summary>
          /// Core class for Schedule E
          /// </summary>
          public class ScheduleERepository : IScheduleERepository
          {
      
              private Cses.Core.Repository.SqlDataContext _context = new Cses.Core.Repository.SqlDataContext();
      
              /// <summary>
              /// constructor
              /// </summary>
              public ScheduleERepository() { }
      
              /// <summary>
              /// constructor for testing
              /// </summary>
              /// <param name="context"></param>
              public ScheduleERepository(Cses.Core.Repository.SqlDataContext context)
              {
                  _context = context;
      
              }
      
              /// <summary>
              /// returns collection of scheduleE values
              /// </summary>
              /// <returns></returns>
              public IQueryable<ScheduleE> GetIQueryableCollection()
              {           
                  return from entity in _context.ScheduleEs                  
                     select new ScheduleE()
                     {    
                          Amount = entity.Amount,
                          NumberOfChildren = entity.NumberChildren,
                          EffectiveDate = entity.EffectiveDate,
                          MonthlyIncome = entity.MonthlyIncome,
                          ModifiedDate = entity.ModifiedDate,
                          ModifiedBy = entity.ModifiedBy,                      
                          Id = entity.Id                          
                     };           
              }
      

      【讨论】:

      • 我的意思不是听起来很刺耳,但我对这段代码有很多反馈。 1) 你不应该在你的数据或领域层中引用 System.Web。 2) 使用像 Windsor 这样的 IOC 容器为每个 Web 请求 (PerWebRequestLifestyle) 限定一个数据上下文,这样您就可以利用缓存、SQL 批处理、事务等。 3) 永远不要吞下异常。 4)将您的查询与“命令”(修改数据库的代码)分开。 5) Compose 方法重构 6) 单一职责原则 7) 永远不要关闭字符串。 Where(x =&gt; x.MonthlyIncome.ToString() == key) 是骇人听闻的。 8) 避免代码生成。
      • 感谢您的洞察力,我将代码缩短到相关部分,System.web 是一个疏忽。 Get Key By string 是使用 Tarintino 的必需接口,为什么要避免代码生成?如果它减少了冗余工作,强制执行一致性等?不明白缺点...
      猜你喜欢
      • 2012-03-10
      • 2011-01-31
      • 1970-01-01
      • 2019-01-17
      • 2017-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多