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

时间:2015-03-17 00:02:28

标签: c# sql entity-framework design-patterns

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

存储库和查询模式是互补的:查询对象表示业务逻辑(WHERE clausules),存储库模式具有Get(IPredicate)方法,该方法接受查询对象并返回SELECT WHERE结果

存储库不应该有业务逻辑:所有业务逻辑必须继续查询对象

目前我有一个包装每个逻辑对象的类(几乎总是单个实体对象),它实现了多个“Get”方法,实现了大多数复杂的查询(连接,groupBy等等),这不是一个好的模式,因为类会因为类似查询的样板代码而增长很多,并且它的公共方法依赖于将使用此类的上下文,因此,使这些类不能用于依赖于同一数据库的多个项目,这是我这个项目重构的主要目标。

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

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

由于

2 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:3)

互联网上有很多存储库模式和工作单元的实现。其中一些非常简单,开发人员基本上手动为每个表自己实现自己的,有些是通用的但不是高级的,有些非常酷,通用,并且仍然提供你做一个体面的地方,投影等的能力。 / p>

我认为良好实施的一个例子可以在这里找到:

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);