Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从经典和DDD角度看存储库中的投影_C#_Domain Driven Design_Repository Pattern - Fatal编程技术网

C# 从经典和DDD角度看存储库中的投影

C# 从经典和DDD角度看存储库中的投影,c#,domain-driven-design,repository-pattern,C#,Domain Driven Design,Repository Pattern,我想谈谈您对存储库模式的看法 在“旧”域概念中(例如从),存储库应该像“内存中的集合”,因此它应该始终返回相同的类型,因此如果需要投影,则必须进行投影,例如,投影将在服务层进行,对吗?或者可以直接进入“域”项目 例如 公共类CustomerRepository { //构造函数接受IRepository 公共IQueryable GetAllDebtors() { //在此处使用IRepository进行查询 } } 相反,在DDD中,存储库,特别是与CQR结合使用的存储库,可以直接返回投影类

我想谈谈您对存储库模式的看法

在“旧”域概念中(例如从),存储库应该像“内存中的集合”,因此它应该始终返回相同的类型,因此如果需要投影,则必须进行投影,例如,投影将在服务层进行,对吗?或者可以直接进入“域”项目

例如

公共类CustomerRepository
{
//构造函数接受IRepository
公共IQueryable GetAllDebtors()
{
//在此处使用IRepository进行查询
}
}
相反,在DDD中,存储库,特别是与CQR结合使用的存储库,可以直接返回投影类型,因为存储库变成了非规范化服务,对吗

例如

公共类CustomerDenmarizer
{
//构造函数*可以*接受IRepository
公共IQueryable GetAllDebtors()
{
//在此处使用IRepository进行查询和投影
}
}

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

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

在“旧”域概念中(例如来自EAAA的p),存储库应该类似于“内存中的集合”,因此它应该始终返回相同的类型,因此如果需要投影,您必须进行投影,因此投影将在服务层进行,例如,对吗

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

在这种结构中,我尝试了两种不同的方法:

  • 实现IQueryable的存储库对于使用域来构建向第三方公开的UI或服务的开发人员来说非常有效,但需要在基础架构中进行大量工作。我们在这方面使用了不同的方法,从Linq2NHibernate到,每种方法都有优点和缺点,但每种方法都非常昂贵。如果您计划使用此技术,请定义好的度量标准,以确保在应用程序开发过程中节省的时间与您在自定义基础架构上花费的时间相等
  • 自定义存储库(那些公开返回
    IEnumerable
    s的方法的存储库)更易于设计和实现,但它们需要UI和服务开发人员付出更多的努力。我们还有一个案例,域规则要求使用自定义存储库,因为用于获取结果的方法也是普适语言的一部分,我们(法律上)被要求授予用于查询的方法与用于表示此类值和谓词的方法相同。
    然而,在自定义存储库中,我们也经常公开投影方法
或者可以直接进入“域”项目

这是可能的,但当你有许多不同的(而且非常复杂的)有界上下文要处理时,这就成了一种痛苦。这就是为什么我对表示普适语言的域类和用于应用程序目的的类使用不同的项目

相反,在DDD中,存储库,特别是与CQR结合使用的存储库,可以直接返回投影类型,因为存储库变成了非规范化服务,对吗

是的,他们可以。

这就是我们对自定义存储库所做的,即使没有CQR。此外,即使某些存储库实现了
IQueryable
,我们偶尔也会公开直接生成投影的方法。

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

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

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

  • 没有通用存储库
  • 没有液体
  • 拥有ICustomerRepository
  • 让CustomerRepository的具体实现充分利用底层存储系统的所有功能
  • 拥有存储库返回预测

    公共接口ICCustomerRepository {

    public IEnumerableGetAllCustomer()

    public IEnumerablegetAlldeborts()

    公共IE
    public class CustomerRepository
    {
        //Constructor accepts an IRepository<Customer>
    
        public IQueryable<Customer> GetAllDebtors()
        {
            //Use IRepository<Customer> here to make the query
        }
    }
    
    public class CustomerDenormalizer
    {
        //Constructor *could* accept an IRepository<Customer>
    
        public IQueryable<Debtor> GetAllDebtors()
        {
            //Use IRepository<Customer> here to make the query and the projection
        }
    }