【问题标题】:How To Implement The Query Side Of CQRS in DDD?如何在 DDD 中实现 CQRS 的查询端?
【发布时间】:2010-12-03 18:34:36
【问题描述】:

我已经使用域模型和存储库实现了 DDD 的命令端,但是如何实现查询端?

我是否为 UI 创建了一个全新的域模型,它保存在项目结构中的什么地方...在域层、UI 层等中?

另外,我使用什么作为查询机制,我是专门为 UI 域对象创建新的存储库,而不是存储库,还是其他?

【问题讨论】:

  • 我刚刚看到 Jak Charlton 的一篇博文,他描述了为什么他决定根本不使用 DDD 进行查询:“CQS 的查询端不需要强类型实体,也不需要强类型实体。类型化的 DTO——因为维护这些实体的主要是临时数据,而 DTO 会消耗不成比例的开发时间来处理 DataTable 可以充分处理的事情”devlicio.us/blogs/casey/archive/2009/06/22/…

标签: domain-driven-design cqrs


【解决方案1】:

根据我对 CQRS 的理解,您将创建一组 DTO,以满足可能需要使用它们的用户界面屏幕或应用程序的要求。

这取决于项目中的需求,因为这取决于您是否要通过 Web 服务公开这些 DTO。 在这种情况下,我不会将它放在 Web 层,而是放在应用程序层或专用的 Façade 层。

然后,您将拥有一个直接填充 DTO 的只读存储库或数据访问层。我认为查询方面应该针对读取性能进行优化,在这种情况下,数据库视图或表上的直接查询/存储过程和 SqlDataReaders 会在这里做得最好。但是绝对值得将这种访问抽象化到接口后面,这样您就可以稍后添加一个缓存的实现。

如果您使用 ORM 并希望从您的域实体映射到 DTO,那么您可以拥有一个通用 QueryRepository,它具有采用 ISpecification 或类似构造来定义查询的方法,然后是用于创建 Dto 的 DtoAssembler 对象从您的域对象。 然后让一个实现为您要执行的每个查询都有一个第一类对象。

这是一个相当人为的例子,但我希望它能给你一个想法。

       public interface ISpecification<T>
        {
            Expression<Func<T, bool>> Predicate { get; }

        }

       public class ActiveCustomersSpecification : ISpecification<Customer>
        {
            private Expression<Func<Customer, bool>> predicate;
            public ActiveCustomersSpecification()
            {
                predicate = c => c.IsActive; 
            }
            #region ISpecicfication<Customer> Members

            public Expression<Func<Customer, bool>> Predicate
            {
                get { return predicate; }
            }

            #endregion
        }

        public interface IQueryRepository<T>
        {
            IQueryable<T> GetQuery(ISpecification<T> specification);

            IEnumerable<T> FindAllBy(ISpecification<T> specification); 
        }



public class CustomerDtoAssembler
    {
        public CustomerDto AssembleFrom(Customer customer)
        {
            var customerDto = new CustomerDto
            {
                Id = customer.Id
            };

            return customerDto; 
        }
    }

【讨论】:

  • 我觉得这很有趣,你能澄清一件事吗?查询库,规范接口,这两者显然都与ORM技术相结合不是吗?在这种情况下,我猜是实体框架。不应该是抽象的吗?
【解决方案2】:

我认为 willbt 给了你一个非常好的starting point

我要补充一点,如果您确实选择继续使用 ORM 作为查询的数据访问策略,那么建议您考虑定义一个针对您期望需要访问的数据量身定制的获取策略(顺便说一下,我在这里专门考虑NHibernate)。这意味着您可以决定是延迟加载还是急切加载与特定 Aggregate Root 对象关联的对象和集合。

Ritesh Rao 的 NCommon project 提供了一个出色的(正在进行中的)演示,展示了如何为不同的目的定义不同的获取策略。

Ritesh explains it really 在他的博客中。

去看看源码吧:

在测试“Repository_For_Uses_​​Registered_Fetching_Strategies”中调用

NHRepository<Order>().For<NHRepositoryTests>()

...导致使用针对 NHRepositoryTests 类注册的获取策略,因此将立即加载 OrderItems 和 Products,而不会弄乱 NHibernate 映射配置。

【讨论】:

  • 这是一个有效的点。但是,它仅在您将实体返回到外观层然后映射到 DTO 时才真正适用。我的建议是使用返回的 IQueryable 并直接投影到 DTO 中。这样您就可以避免任何 FetchStrategies。您甚至可以在 NHibernate 映射级别进行投影。
  • 当然!对了谢谢。我仍然在接受 NHibernate.Linq 如何改变游戏规则,但是如果你看看 Ritesh 如何接受 IQueryable 你会发现他确实“明白了”并且正在围绕它构建好的东西(即规范需要一个构造函数中的表达式)。
猜你喜欢
  • 1970-01-01
  • 2014-10-21
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多