存储库和查询对象模式。如何实现复杂查询

Repository and query objects pattern. How to implement complex queries

我已经阅读了很多关于存储库模式的帖子,但是有一些实际问题他们似乎没有解决或解释。这是我对这两种模式的理解:

存储库和查询模式是互补的:查询对象表示业务逻辑(WHERE 子句),存储库模式有一个 Get(IPredicate) 方法,它接受一个查询对象和returns 一个 SELECT WHERE 结果

存储库不应该有业务逻辑:所有的业务逻辑都必须在查询对象上进行

目前我有一个 class 包装每个逻辑对象(几乎总是单个实体对象),实现多个“Get”方法,实现最复杂的查询(连接、groupBy 等... ),这不是一个好的模式,因为 classes 往往会增长很多,因为类似查询的样板代码及其 public 方法取决于将使用此 class 的上下文,因此,使此 classes 无法用于依赖于同一数据库的多个项目,这是我此项目重构的主要目标。

如何使用这两种模式实现比单个 SELECT WHERE 更复杂的查询而不会将业务逻辑泄漏到存储库中?

或者如果此业务逻辑不适合存储库或查询对象 这个逻辑在哪里合适?

Repository 模式适用于标准 CRUD 应用程序。您需要在数据库中针对单个 table 实施经典的创建、读取、更新和删除操作集。在这种情况下,您为每个 table 创建一个存储库,并允许读取操作具有额外的值,以便可以应用过滤。

在下一级,您有 工作单元 模式。这些用于跨越多个存储库并执行业务操作。因此,例如,您将从多个存储库读取值,执行计算,然后将更改写回到多个存储库。所有这些都将发生在一个事务中,因此您在数据库中始终具有一致的状态。

问题是当您有跨越多个 table 的复杂查询时。在这种情况下,您可以将查询放入存储库中,该存储库是查询 from 子句中的第一个 table。然后您需要为该存储库方法提供参数,以便可以根据需要对其进行参数化。

在 Internet 上流传着许多存储库模式和工作单元的实现。其中一些非常简单,开发人员基本上自己手动为每个 table 实现自己的功能,一些是通用的但不高级,还有一些非常酷,通用并且仍然可以让你做一个像样的地方,投影和之类的

可以在此处找到我认为良好实施的示例:

https://genericunitofworkandrepositories.codeplex.com/

它是针对MVC的,由界面显示。我专注于 WPF 应用程序,因此我需要对其进行一些调整。但是这个工作单元实现的思路还是不错的。

此实现有缺点。因为它依赖于一些高级 LINQ 和 EF 功能,所以有人可能会争辩说您的底层访问层正在感染存储库层和使用存储库的层。

要点是,例如,当您想离开 EF 时,您可能不得不更改存储库的界面。

为了展示这个库的强大功能,一些代码片段可以证明这一点:

_fotoRepository = unitOfWork.RepositoryAsync<Foto>();
var fotos = await _fotoRepository
            .Query(r => r.BestelBonId == bestelBonId || werkstukids.Contains(r.WerkstukMetBewerkingenId.Value))
            .SelectAsync()
            .ConfigureAwait(false);

或使用投影:

IRepository<Relatie> relatieRepository = unitOfWork.RepositoryAsync<Relatie>();
        var relatiesOverviewsEnumerable = relatieRepository
            .Query()
            .NoTracking()
            .OrderBy(q => q.OrderBy(d => d.RelatieId))
            .Select(b => new RelatieOverview
            {
                RelatieId = b.RelatieId,
                Naam = b.Naam,
                BTW = b.BTW,
                HoofdAdres = b.Adressen.FirstOrDefault(a => a.AdresTypeId == HoofdadresType)
            });
        _relatieOverviews = new ObservableCollection<RelatieOverview>(relatiesOverviewsEnumerable);