代码优先 - 存储库模式 - 设计注意事项
Code First - Repository Pattern - Design Considerations
我正在尝试制作一个 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 是代码优先实体(不是业务对象)。理想情况下,存储库应该处理 (accept+return) 它们还是业务对象本身?
- 存储库应该 return IQueryable 还是 IEnumerable?
- 如果问题 #1 的答案是业务对象,那么如何
实现实体和业务对象之间的映射?
- 如果我引入一个新的服务层(这将是
由客户端消费),服务层将是调用存储库方法和映射的一次。这是正确的吗?
- 如果以上问题的答案是肯定的,那么在做映射
服务层打破了单一职责原则。如何获得
结束了吗?
我也欢迎 link 实现了存储库和 UnitOfWork 的示例应用程序(MVC、EF、SQL 服务器)。
软件设计没有对错之分,但据我所知,有一些设计实践可以回答您的问题。
The IEntity which are handled in the interface are code first entities
(not business objects). Is ideally a Repository expected to handle
(accept+return) them or the business objects itself?
- 理想情况下,存储库层应该只处理实体对象。不要用业务对象和映射逻辑淹没它
Should a Repository return IQueryable or IEnumerable?
- 我更愿意用
Iqueryable
,因为Iqueryable
也继承自IEnumerable
,所以IEnumerable
能做的事,IQueryable
也能做.更重要的是,每个使用 Iqueryable
的查询尝试都将在 database
层中执行。所以总而言之,如果您不确定是否还需要执行任何额外的查询(例如:过滤数据),IQueryable
绝对是必须的。
If the answer for the Question #1 is business object, then how to
implement mapping between Entities and Business objects?
- 有很多方法可以进行映射,
AutoMapper
是用于此目的的良好且稳定的库。
If I introduce a new service layer (which will be consumed by the
client), the service layer will be the once which calls the Repository
methods, and mapping. Is this correct?
这实际上取决于您如何设计 服务层。通常的流程是:
调用Repository
方法=>获取数据=>映射到业务对象=>执行额外的逻辑=>return业务对象
If the answer to the above question is yes, then doing mapping in
service layer breaks Single Responsibility Principle. How to get over
it?
正如单一职责原则的定义(一个class应该只有一个改变的理由),你的服务层职责是在业务对象,所以我会说它不会违反 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;
}
- The IEntity which are handled in the interface are code first entities (not business objects). Is ideally a Repository expected to handle (accept+return) them or the business objects itself?
您是否有任何理由拥有单独的域模型(业务对象)和持久性模型(代码优先实体)? EF 对代码优先没有太多额外要求类,通常你可以直接持久化你的业务对象。
如果您选择有一个单独的持久性模型,那么它应该是存储库的实现细节。存储库应与业务对象一起使用。
- Should a Repository return IQueryable or IEnumerable?
视情况而定。 IQueryable
无需修改存储库即可轻松在应用层创建查询。当您有一个单独的简单读取堆栈时,它在 CQRS 中特别有用。
您必须知道,使用 IQueryable
会引入对基础数据源的依赖。当您更改数据源时,适用于一个数据源的查询可能会在运行时失败。
- If the answer for the Question #1 is business object, then how to implement mapping between Entities and Business objects?
您可以使用像 Automapper 这样的工具。
- If I introduce a new service layer (which will be consumed by the client), the service layer will be the once which calls the Repository methods, and mapping. Is this correct?
服务层将调用存储库。存储库将 return/add/modify 一个业务对象。任何映射(如有必要)都将在存储库中完成。
我正在尝试制作一个 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 是代码优先实体(不是业务对象)。理想情况下,存储库应该处理 (accept+return) 它们还是业务对象本身?
- 存储库应该 return IQueryable 还是 IEnumerable?
- 如果问题 #1 的答案是业务对象,那么如何 实现实体和业务对象之间的映射?
- 如果我引入一个新的服务层(这将是 由客户端消费),服务层将是调用存储库方法和映射的一次。这是正确的吗?
- 如果以上问题的答案是肯定的,那么在做映射 服务层打破了单一职责原则。如何获得 结束了吗?
我也欢迎 link 实现了存储库和 UnitOfWork 的示例应用程序(MVC、EF、SQL 服务器)。
软件设计没有对错之分,但据我所知,有一些设计实践可以回答您的问题。
The IEntity which are handled in the interface are code first entities (not business objects). Is ideally a Repository expected to handle (accept+return) them or the business objects itself?
- 理想情况下,存储库层应该只处理实体对象。不要用业务对象和映射逻辑淹没它
Should a Repository return IQueryable or IEnumerable?
- 我更愿意用
Iqueryable
,因为Iqueryable
也继承自IEnumerable
,所以IEnumerable
能做的事,IQueryable
也能做.更重要的是,每个使用Iqueryable
的查询尝试都将在database
层中执行。所以总而言之,如果您不确定是否还需要执行任何额外的查询(例如:过滤数据),IQueryable
绝对是必须的。
If the answer for the Question #1 is business object, then how to implement mapping between Entities and Business objects?
- 有很多方法可以进行映射,
AutoMapper
是用于此目的的良好且稳定的库。
If I introduce a new service layer (which will be consumed by the client), the service layer will be the once which calls the Repository methods, and mapping. Is this correct?
这实际上取决于您如何设计 服务层。通常的流程是:
调用
Repository
方法=>获取数据=>映射到业务对象=>执行额外的逻辑=>return业务对象
If the answer to the above question is yes, then doing mapping in service layer breaks Single Responsibility Principle. How to get over it?
正如单一职责原则的定义(一个class应该只有一个改变的理由),你的服务层职责是在业务对象,所以我会说它不会违反 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;
}
- The IEntity which are handled in the interface are code first entities (not business objects). Is ideally a Repository expected to handle (accept+return) them or the business objects itself?
您是否有任何理由拥有单独的域模型(业务对象)和持久性模型(代码优先实体)? EF 对代码优先没有太多额外要求类,通常你可以直接持久化你的业务对象。
如果您选择有一个单独的持久性模型,那么它应该是存储库的实现细节。存储库应与业务对象一起使用。
- Should a Repository return IQueryable or IEnumerable?
视情况而定。 IQueryable
无需修改存储库即可轻松在应用层创建查询。当您有一个单独的简单读取堆栈时,它在 CQRS 中特别有用。
您必须知道,使用 IQueryable
会引入对基础数据源的依赖。当您更改数据源时,适用于一个数据源的查询可能会在运行时失败。
- If the answer for the Question #1 is business object, then how to implement mapping between Entities and Business objects?
您可以使用像 Automapper 这样的工具。
- If I introduce a new service layer (which will be consumed by the client), the service layer will be the once which calls the Repository methods, and mapping. Is this correct?
服务层将调用存储库。存储库将 return/add/modify 一个业务对象。任何映射(如有必要)都将在存储库中完成。