代码优先 - 存储库模式 - 设计注意事项

本文关键字:注意事项 模式 存储 代码 | 更新日期: 2023-09-27 18:37:08

我正在尝试创建一个Repository+UnitOfWork平台。我的 IRepository 界面如下所示。

 public interface IRepository<TEntity>
        where TEntity : IEntity
    {
        IQueryable<TEntity> GetAll();
        TEntity Get(int id);
        IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate);
        TEntity Add(TEntity entity);
        TEntity Delete(TEntity entity);
        void Save(TEntity entity);
    }

我对以下一些问题感到困惑...

  1. 在接口中处理的 IEntity 是代码优先实体(不是业务对象)。理想情况下,存储库应该处理(接受+返回)它们还是业务对象本身?
  2. 存储库应该返回 IQueryable 还是 IEnumerable?
  3. 如果问题 #1 的答案是业务对象,那么如何实现实体和业务对象之间的映射?
  4. 如果我引入一个新的服务层(这将是由客户端使用),服务层将是调用存储库方法和映射的一次。这是对的吗?
  5. 如果上述问题的答案是肯定的,那么在服务层打破了单一责任原则。如何获得在上面?

我也欢迎一个示例应用程序(MVC,EF,SQL SERVER)的链接,其中实现了存储库和UnitOfWork。

代码优先 - 存储库模式 - 设计注意事项

软件设计没有对错之分,但据我所知,有一些设计实践可以回答你的问题。

接口中处理的 IEntity 是代码优先实体 (不是业务对象)。理想情况下是期望处理的存储库 (接受+返回)它们还是业务对象本身?

  • 理想情况下,存储库层应仅处理实体对象。不要用业务对象和映射逻辑淹没它

存储库应该返回 IQueryable 还是 IEnumerable?

  • 我更喜欢使用 Iqueryable ,因为Iqueryable也继承自IEnumerable,所以IEnumerable可以做的每一件事,IQueryable也可以做。更重要的是,每个带有Iqueryable的查询都将database层中执行。因此,总而言之,如果您不确定是否仍需要执行任何额外的查询(例如:过滤数据),IQueryable绝对是必须的。

如果问题 #1 的答案是业务对象,那么如何 实现实体和业务对象之间的映射?

    有很多
  • 方法可以进行映射,AutoMapper是一个很好的稳定库。

如果我引入一个新的服务层(将被 client),服务层将是调用存储库的一次 方法和映射。这是对的吗?

  • 这实际上取决于您如何设计服务层。通常的流程是:

    调用Repository方法 => 获取数据 =>映射到业务对象 =>

    执行额外的逻辑 =>返回业务对象

如果上述问题的答案是肯定的,那么在 服务层打破了单一责任原则。如何克服 它?

就像在单一责任原则的定义中一样(一个类应该只有一个原因可以更改),你的服务层职责是对业务对象执行额外的逻辑,所以我想说它不违反 SRP。

public SampleDTO SampleServiceMethod(InputModel input)
{
    var model = _sampleRepository.FindBy(input.Id);
    var dto = SampleMapper.ToSampleDto(model);
    // do something and return the dto
    dto.Test = 1;
    return dto;
}
  1. 在接口中处理的 IEntity 是代码优先实体(不是业务对象)。理想情况下,存储库应该处理(接受+返回)它们还是业务对象本身?

您是否有任何理由拥有单独的域模型(业务对象)和持久性模型(代码优先实体)?EF 对代码优先类没有太多额外要求,通常可以直接保留业务对象。

如果您选择使用单独的持久性模型,则它应该是存储库的实现详细信息。存储库应使用业务对象。

  1. 存储库应该返回 IQueryable 还是 IEnumerable?

这要看情况。 IQueryable使得在应用程序层中创建查询变得容易,而无需修改存储库。当您具有单独的简单读取堆栈时,它在 CQRS 中特别有用。

您必须知道,使用 IQueryable 会引入对基础数据源的依赖关系。更改数据源时,使用一个数据源的查询可能会在运行时失败。

  1. 如果问题 #1 的答案是业务对象,那么如何实现实体和业务对象之间的映射?

您可以使用自动映射器等工具。

  1. 如果我引入一个新的服务层(将由客户端使用),则服务层将是调用存储库方法和映射的一次。这是对的吗?

服务层将调用存储库。存储库将返回/添加/修改业务对象。任何映射(如有必要)都将在存储库中完成。