我计划将我们的数据访问层迁移到使用仓储模式和工作单元。
我知道仓储库将帮助我轻松更改持久性存储(数据库,集合等)和技术,如EF到MongoDB。因此,我注意到了一些仓储实现的关键点,例如:
- 返回
IEnumerable
而不是IQueryable
- 仓储应该仅负责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)作为控制器中模型和视图模型之间的中间类,并使用映射器来映射属性。
如果我将关键注释保留在存储库上,那么我需要进行多次往返数据库以获取数据,而且它会返回整个模型而不是有用的列。但是,如果我将这些方法迁移到存储库中,就会破坏存储库模式,因为它将包含业务逻辑和返回类型而不是模型。
因此问题是,在这种情况下我该怎么办?请给我一些建议,帮助我找到正确的方向。
非常感谢。
IEnumerable<T>
,但我认为使用IQueryable<T>
也没有什么问题(它与IEnumerable<T>
一样是 .NET BCL 的一部分)。但即使你想返回IEnumerable<T>
,你也可以在实际返回值中使用IQueryable<T>
,因为它扩展了IEnumerable<T>
。所以在你的示例中没有必要调用ToList()
。这里有一个类似的问题:https://dev59.com/FFgQ5IYBdhLWcg3wdzvX#42736117 - Akos NagyIQueryable<T>
,并让服务层执行其需要执行的操作吗? - vietvoquocIQueryable<T>
,你确实需要在业务逻辑层调用ToList()
,老实说,这会有点泄露抽象层。但是,在 .NET 中,IQueryable<T>
和延迟执行已经集成得如此完美,我认为这并不是一个非常严重的问题。 - Akos Nagy