c# - 应该在 Repository 或 Service 层编写复杂的查询?

标签 c# entity-framework repository-pattern

我正计划将我们的数据访问层迁移到使用存储库模式和工作单元。

我知道存储库将帮助我轻松地将持久性存储(数据库、集合等)和 EF 等技术更改为 MongoDB。所以我注意到存储库实现的一些关键点,例如:

  1. 返回 IEnumerable 而不是 IQueryable
  2. Repository 应该只负责 CRUD 操作
  3. 存储库方法的返回类型应该是模型(实体)
  4. 只为聚合根实现存储库

如果我在项目中实现存储库时应用这些关键点,我将完全失去如何处理与多个实体相关的复杂查询。

目前我已经拥有的是,在具有大量服务类的 BLL 库上,将直接联系 EF 的 DbContextDbSet 以及一些验证,如下所示:

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 方法。它还可能返回复杂的对象图。它可能会进行复杂的查询。也就是说,使用 GetGetById 等简单方法,它也可能使用复杂方法,例如 GetTopBrokenVehicles(vehicleType, top)。如果您为复杂查询编写单独的方法,那绝对没问题。

挑战在于,您如何接受必要的参数。您可以接受内联参数或构建单独的简单输入参数类。

这是 Repository 的示例代码和 UoW .

关于c# - 应该在 Repository 或 Service 层编写复杂的查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50312714/

相关文章:

c# - 将存储库模式与(例如)DevExpress XPO 一起使用是否有意义?

asp.net-mvc - 如何避免存储库重复代码

c# - C#中Javascript异常消息

c# - 如何使用自定义类型初始化数组

c# - 自动展开PropertyGrid中的一些属性

c# - Entity Framework ——幕后 : DataReaders and connection life period

string - Entity Framework 和 Oracle : Cannot Insert VARCHAR2 > 1, 999 个字符

c# - 使用 content(body) 或多个参数的 restful API get 方法

c# - 如何告诉 Entity Framework 仅保存特定 DbSet 的更改?

c# - 无法更新外键引用(导航属性)