如何在DDD中实现CQRS的查询端?

时间:2009-10-04 18:21:43

标签: domain-driven-design cqrs

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

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

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

2 个答案:

答案 0 :(得分:6)

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

如果您要通过Web服务公开这些DTO,项目中存在的内容基于要求。 在这种情况下,我不会将它放在Web层中,而是放在Application层或专用的Façade层中。

然后您将拥有一个只读存储库或数据访问层,它直接填充DTO。我认为事情的查询方面应该针对读取性能进行优化,在这种情况下,数据库视图或表和SqlDataReaders上的直接查询/存储过程将在这里做得最好。但是在界面背后提取这种访问权限肯定是值得的,因此您可以在以后的轨道中添加缓存实现。

如果您正在使用ORM并希望从您的域实体映射到DTO,那么您可以拥有一个通用的QueryRepository,其中包含用于定义查询的ISpecification或类似构造的方法,然后是用于创建Dtos的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; 
        }
    }

答案 1 :(得分:3)

我认为 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映射配置。