应该在存储库或服务层中编写复杂的查询吗? [英] Should write complex query in Repository or Service layer?

查看:47
本文介绍了应该在存储库或服务层中编写复杂的查询吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I are planning migrate our data access layer to using repository pattern and unit of work.

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

I do know repository will help me to change persistence store (database, collection...etc) and technology such as EF to MongoDB easily. So I noticed some key points of implementation of a repository such as:


  1. 返回 IEnumerable 而不是 IQueryable

  2. 存储库应仅负责CRUD操作

  3. 返回类型存储库方法应为模型(实体)

  4. 仅实现聚合根存储库

  1. Return IEnumerable instead of IQueryable
  2. Repository should take responsibilities for CRUD operations only
  3. Return type of repository method should be model (entity)
  4. Only implement repository for aggregate root

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

If I apply these key points during implement repository in my project, I totally lost how to deal with complex query in which related to multiple entities.

当前我已经拥有的是具有大量服务类的BLL库将直接与EF的 DbContext DbSet 进行联系,并进行如下验证:

Currently what I already had was that on BLL library with a lot of services class will contact directly to DbContext and DbSet of EF and some of validation like this:

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)作为两者之间的中间类

I am currently using Data Transfer Object (DTO) to be the middle classes between model and viewmodel on controller and using Mapper to map properties.

如果我在上面的存储库上保存了关键说明,则需要多次往返数据库以获取数据,并且它将返回整个模型,而不是有用的列。但是,如果我将这类方法迁移到存储库,则会破坏存储库模式,因为它将包含业务逻辑并且返回类型不是模型。

If I keep key notes on repository above I need to do multiple round trip to database for getting data, and it will return whole model instead of useful columns. But if I migrate those kind of methods to repository I will broken repository pattern because it will contain business logic and return type not an model.

所以问题是我应该怎么做在这种情况下?请给我一些建议,以使我步入正轨。

So question is what should I do in this case? Please give me some advise to put me on the right track.

非常感谢。

推荐答案

这取决于意见和用例,但我个人不同意您提到的一些关键点。

This depends on opinion and the use case, but I personally do not agree with some of the key points you mentioned.


返回IEnumerable而不是IQueryable

Return IEnumerable instead of IQueryable

同意。返回 IQueryable 破坏了存储库存在的基本目的。网上有很多文章解释了这如何带来比解决方案更多的问题。虽然,我学会了永不言败。请参考。或者只是搜索 google

Agree. Returning IQueryable defeats basic purpose of existence of Repository. There are lot many articles on net explaining how this creates more problem than a solution. Though, I have learned to never say never. Refer this, this, or this. Or simply search google.


存储库应仅负责CRUD操作

Repository should take responsibilities for CRUD operations only

同意。使用简单的CRUD,它也可以执行复杂的读取和写入操作。我的经验表明,在特殊情况下,如果要在RDBMS端实现它,则必须将业务逻辑的一部分放入存储库中。这不是对还是错。如果您知道自己在做什么,就不会有问题。

Agree. With simple CRUD, it may also do complex reads and writes. My experience tell that in exceptional cases, you have to put a part of business logic in repository if you want to implement it on RDBMS side. This is not right or wrong. If you know what you are doing, there should not be an issue.


存储库方法的返回类型应该是模型(实体)

Return type of repository method should be model (entity)

如果您未使用DDD,则可以。否则,是实施决定。对于像EF或NHibernate这样的完整ORM,最好直接返回Domain Model,而不是每个表Entity实例。

If you are not using DDD, then yes. Otherwise, it is implementation decision. With full ORM like EF or NHibernate, it is better to return Domain Model directly instead of per table Entity instance.

始终建议存储库应返回Domain Model。这样,从RDBMS返回的数据与域模型的映射(反之亦然)成为存储库的责任。这样避免了将持久性问题泄漏到存储库外部的必要性,从而使其余的应用程序持久性变得无知。

It is always suggested that Repository should return Domain Model. That way, mapping of data returned from RDBMS with the Domain Model (and vice versa) becomes responsibility of repository. This avoids necessity of leaking the persistence concerns outside the repository and thus makes your rest of the application persistence ignorant.

但是,并非每个应用程序都实现DDD。许多小型应用程序设计实体将它们与数据库设计一对一映射。在这种情况下,存储库可能会返回实体(等效于您的表和字段)本身,并且映射成为调用代码的责任。或者,存储库可以映射必要的模型并返回模型本身。强烈建议不要这样做,因为存在上述问题。这样,您就不得不放弃完整的ORM提供的某些功能。

But, not every application implement DDD. Many small applications design entities those are mapped 1 to 1 with their database design. In this case, repository may return entity (which is equivalent to your table and fields) itself and mapping becomes responsibility of calling code. Or, repository may map the necessary model and return the model itself. This is strongly discouraged because the problems stated above. With this, you have to give up some of the features full ORMs provide.

所有这些取决于您的问题是什么,设计目标是什么,应用程序的大小以及

All this depends on what is your problem, what are your design objectives, size of application and other design patterns implemented etc. That is why it becomes design decision.


仅实现汇总根的存储库

Only implement repository for aggregate root

同意使用DDD。如果没有,则像每个表存储库一样有多个选择。再次,取决于用例。

Agreed if it is with DDD. If not, multiple choices are available like per table repository. Again, depends on use case.

关于复杂查询

不是信息库只应实现简单的CRUD方法是必要的。它还可能返回复杂的对象图。它可能会执行复杂的查询。也就是说,使用 Get GetById 等简单方法,它可能还会使用诸如 GetTopBrokenVehicles(vehicleType,顶部)。如果您为复杂的查询编写单独的方法,那绝对没问题。

It is not necessary that repositories should only implement simple CRUD methods. It may also return complex object graph. It may do complex querying. That said, with simple methods like Get, GetById etc, it may also consume complex methods like GetTopBrokenVehicles(vehicleType, top). It is absolutely fine if you write separate method for complex query.

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

Challenge is that, how you accept the necessary parameters. You may accept the parameters inline or build separate simple input parameter class.

此处是存储库 UoW

这篇关于应该在存储库或服务层中编写复杂的查询吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆