代码优先 - 存储库模式 - 设计注意事项
本文关键字:注意事项 模式 存储 代码 | 更新日期: 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);
}
我对以下一些问题感到困惑...
- 在接口中处理的 IEntity 是代码优先实体(不是业务对象)。理想情况下,存储库应该处理(接受+返回)它们还是业务对象本身?
- 存储库应该返回 IQueryable 还是 IEnumerable?
- 如果问题 #1 的答案是业务对象,那么如何实现实体和业务对象之间的映射?
- 如果我引入一个新的服务层(这将是由客户端使用),服务层将是调用存储库方法和映射的一次。这是对的吗?
- 如果上述问题的答案是肯定的,那么在服务层打破了单一责任原则。如何获得在上面?
我也欢迎一个示例应用程序(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;
}
- 在接口中处理的 IEntity 是代码优先实体(不是业务对象)。理想情况下,存储库应该处理(接受+返回)它们还是业务对象本身?
您是否有任何理由拥有单独的域模型(业务对象)和持久性模型(代码优先实体)?EF 对代码优先类没有太多额外要求,通常可以直接保留业务对象。
如果您选择使用单独的持久性模型,则它应该是存储库的实现详细信息。存储库应使用业务对象。
- 存储库应该返回 IQueryable 还是 IEnumerable?
这要看情况。 IQueryable
使得在应用程序层中创建查询变得容易,而无需修改存储库。当您具有单独的简单读取堆栈时,它在 CQRS 中特别有用。
您必须知道,使用 IQueryable
会引入对基础数据源的依赖关系。更改数据源时,使用一个数据源的查询可能会在运行时失败。
- 如果问题 #1 的答案是业务对象,那么如何实现实体和业务对象之间的映射?
您可以使用自动映射器等工具。
- 如果我引入一个新的服务层(将由客户端使用),则服务层将是调用存储库方法和映射的一次。这是对的吗?
服务层将调用存储库。存储库将返回/添加/修改业务对象。任何映射(如有必要)都将在存储库中完成。