2

我会就您如何看待存储库模式发表意见。

在“旧”域概念中(例如来自EAAA 的 P),存储库应该像“内存中的集合”,所以它应该总是返回相同的类型,所以如果你需要一个投影,你必须做出来,所以例如,投影将在服务层中进行,对吗?还是可以直接进入“域”项目?

例如

public class CustomerRepository
{
    //Constructor accepts an IRepository<Customer>

    public IQueryable<Customer> GetAllDebtors()
    {
        //Use IRepository<Customer> here to make the query
    }
}

相反,在 DDD 中,存储库,尤其是与 CQRS 结合使用,可以直接返回投影类型,因为存储库成为非规范化服务,对吧?

例如

public class CustomerDenormalizer
{
    //Constructor *could* accept an IRepository<Customer>

    public IQueryable<Debtor> GetAllDebtors()
    {
        //Use IRepository<Customer> here to make the query and the projection
    }
}
4

4 回答 4

1

IMO,与“内存中”集合的对应被过分强调了。存储库不应该隐藏它封装了一些繁重的 IO 的事实——这将是一个泄漏的抽象。此外,IQueryable<T>这也是一个泄漏的抽象,因为几乎没有任何提供者会支持所有操作。我建议将尽可能多的项目委托给数据库,因为它非常擅长。

CQRS 中的投影有些不同。它通常被实现为一个事件消费者,它更新存储在一些底层存储机制中的数据结构,这些机制本身可能是 SQL 服务器或键值存储。主要区别在于,在这种情况下,是对来自消息队列的事件的投影响应。这些事件可能来自外部系统。

于 2013-04-04T15:23:25.887 回答
1

在“旧”域概念(例如来自 EAAA 的 P)中,存储库应该像一个“内存中的集合”,所以它应该总是返回相同的类型,所以如果你需要一个投影,你必须把它弄出来,所以例如,投影将在服务层中进行,对吗?

在我自己的解决方案中,我区分了领域模型(这是我从领域专家那里学到的语言的 C# 表达式,几乎是内部 DSL)和与领域相关的应用程序关注点(例如与应用程序相关的存储库)需要坚持)。这意味着它们在不同的项目中编码。

在这样的结构中,我尝试了两种不同的方法:可查询存储库和自定义存储库

  • 实现 IQueryable 的存储库对于使用该域构建 UI 或向第三方公开的服务的开发人员来说非常有效,但需要在基础架构方面进行大量工作。我们在这方面使用了不同的方法,从 Linq2NHibernate 到re-linq,各有利弊,但每一个都相当昂贵。如果您打算使用此技术,请定义良好的指标以确保您在应用程序开发期间节省的时间值得您花在自定义基础架构上的时间。
  • 自定义存储库(那些公开返回IEnumerables 的方法)更容易设计和实现,但它们需要 UI 和服务的开发人员付出更多的努力。我们还有一个案例,域规则需要使用自定义存储库,因为用于获取结果的查询对象是规范,也是通用语言的一部分,我们(法律上)需要授予用于查询的方法是同样用来表示这样的值和谓词。
    但是,在自定义存储库中,我们也经常公开投影方法。

还是可以直接进入“域”项目?

这是可能的,但是当您有许多不同(并且非常复杂)的有界上下文要使用时,它就会变得很痛苦。这就是为什么我为表达普遍存在的语言的领域类和服务于应用目的的类使用不同的项目。

相反,在 DDD 中,存储库,尤其是与 CQRS 结合使用,可以直接返回投影类型,因为存储库成为非规范化服务,对吧?

是的他们可以。
这就是我们对自定义存储库所做的事情,即使没有 CQRS。此外,即使有一些存储库实现IQueryable,我们偶尔也会暴露直接产生投影的方法。

于 2013-04-05T09:58:56.927 回答
1

说“原始形式”的存储库必须只返回相同实体类型的对象有些夸张。例如,人们一直Count()在他们的存储库中包含方法或其他计算 - 这甚至在 Evan 的蓝皮书中都有记录。

另一方面,我不确定您所说的“非规范化类型”是什么意思,但如果这是从几个不同实体借用以按原样或合并方式公开其数据或公开单个域实体的部分视图的类型,我倾向于认为它不再是域。事实证明,它们通常用于特定于应用程序的目的,例如生成 Excel 报告或显示统计数据或摘要屏幕。

如果是这种情况,并且出于性能原因,我想直接利用数据库而不是依赖域,我更愿意创建一个单独的项目,在其中放置所有这些“报告”相关逻辑。没关系,如果您仍然将数据访问对象命名为 Repositories 那里(毕竟,它们也是内存中集合的错觉,只是其他类型的集合)。

于 2013-04-05T12:22:08.677 回答
0
  • 没有通用存储库。
  • 没有 IQueryable。
  • 拥有 ICustomerRepository。
  • 让您的 CustomerRepository 的特定实现利用底层存储系统的所有花里胡哨。
  • 有存储库返回预测。

    公共接口 ICustomerRepository {

    公共 IEnumerable<客户> GetAllCustomer()

    公共 IEnumerable<债务人> GetAllDebtors()

    公共 IEnumerable<CustomerSummary> GetCustomerSummaryByName(字符串名称)

    公共 IEnumerable<CustomerSummary> GetCustomerSummaryById(string id) }

于 2015-06-28T10:45:27.620 回答