我正计划将我们的数据访问层迁移到使用存储库模式和工作单元。
我知道存储库将帮助我轻松地将持久性存储(数据库、集合等)和 EF 等技术更改为 MongoDB。所以我注意到存储库实现的一些关键点,例如:
- 返回
IEnumerable
而不是IQueryable
- Repository 应该只负责 CRUD 操作
- 存储库方法的返回类型应该是模型(实体)
- 只为聚合根实现存储库
如果我在项目中实现存储库时应用这些关键点,我将完全失去如何处理与多个实体相关的复杂查询。
目前我已经拥有的是,在具有大量服务类的 BLL 库上,将直接联系 EF 的 DbContext
和 DbSet
以及一些验证,如下所示:
public IEnumerable<ProjectDTO> GetProjectWithDetails()
{
// Validation
// Logging
// Can be any logic need to before query data.
Dbcontext.Projects.Where(p =>
// multiple of conditions go here follow business rules
// conditions will need to check another entities (task, phase, employee...) such as:
// 1. project have task status 'in-progress' .. etc
// 2. project have employeeid 1,2,3..
// 3. project have stask start at some specific date.
// 4....
)
.Select(p => new ProjectDTO
{
Label = p.Label,
Phase = new PhaseDTO{
Label = p.Phase.Label,
Tasks = p.Phase.Tasks.Select(t => new TaskDTO{
// some related properties
})
}
}).ToList();
}
我目前正在使用数据传输对象 (DTO) 作为 Controller 上模型和 View 模型之间的中间类,并使用 Mapper 映射属性。
如果我在上面的存储库中保留关键注释,我需要多次往返数据库以获取数据,并且它将返回整个模型而不是有用的列。但是,如果我将这些方法迁移到存储库,我将破坏存储库模式,因为它将包含业务逻辑和返回类型而不是模型。
所以问题是在这种情况下我应该怎么做?请给我一些建议,让我走上正轨。
非常感谢。
最佳答案
这取决于意见和用例,但我个人不同意你提到的一些关键点。
Return IEnumerable instead of IQueryable
同意。返回 IQueryable
违背了 Repository 存在的基本目的。网上有很多文章解释了这如何产生比解决方案更多的问题。虽然,我学会了永不言败。引用this , this , 或 this .或者直接搜索 google .
Repository should take responsibilities for CRUD operations only
同意。通过简单的 CRUD,它还可以进行复杂的读写。我的经验告诉我,在特殊情况下,如果你想在 RDBMS 端实现它,你必须将一部分业务逻辑放在存储库中。这没有对错之分。如果您知道自己在做什么,就不会有问题。
Return type of repository method should be model (entity)
如果您不使用 DDD,那么可以。否则为执行决定。使用像 EF 或 NHibernate 这样的完整 ORM,最好直接返回域模型而不是每个表实体实例。
总是建议 Repository 应该返回 Domain Model。这样,从 RDBMS 返回的数据与域模型的映射(反之亦然)成为存储库的责任。这避免了将持久性问题泄露到存储库之外的必要性,从而避免了应用程序持久性的其余部分一无所知。
但是,并不是每个应用程序都实现 DDD。许多小型应用程序设计实体与它们的数据库设计一对一映射。在这种情况下,存储库可能会返回实体(相当于您的表和字段)本身,并且映射成为调用代码的责任。或者,存储库可以映射必要的模型并返回模型本身。强烈建议不要这样做,因为存在上述问题。因此,您必须放弃完整的 ORM 提供的一些功能。
所有这一切都取决于您的问题是什么、您的设计目标是什么、应用程序的大小以及实现的其他设计模式等。这就是为什么它成为设计决策。
Only implement repository for aggregate root
同意是否与 DDD 一起使用。如果没有,可以像每个表存储库一样提供多种选择。同样,取决于用例。
关于复杂查询
存储库不必只实现简单的 CRUD 方法。它还可能返回复杂的对象图。它可能会进行复杂的查询。也就是说,使用 Get
、GetById
等简单方法,它也可能使用复杂方法,例如 GetTopBrokenVehicles(vehicleType, top)
。如果您为复杂查询编写单独的方法,那绝对没问题。
挑战在于,您如何接受必要的参数。您可以接受内联参数或构建单独的简单输入参数类。
这是 Repository 的示例代码和 UoW .
关于c# - 应该在 Repository 或 Service 层编写复杂的查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50312714/