Подтвердить что ты не робот

Как реализовать сторону запроса CQRS в DDD?

Я реализовал командную часть DDD с использованием модели и репозиториев домена, но как я могу реализовать сторону запроса?

Я создаю полностью новую модель домена для пользовательского интерфейса и где это хранится в структуре проекта... в доменном слое, слое пользовательского интерфейса и т.д.?

Кроме того, что я использую в качестве механизма запросов, я создаю новые репозитории специально для объектов домена UI, что-то другое, кроме репозиториев, или что-то еще?

4b9b3361

Ответ 1

Из моего понимания CQRS вы создадите набор DTO, которые отвечают требованиям экранов пользовательского интерфейса или приложений, которые могут их потреблять.

Если это существует в проекте, оно основано на требованиях, поскольку это будет зависеть, если вы собираетесь разоблачить эти DTO через веб-службы. В этом случае я бы не поместил его в веб-слой, а скорее в уровень приложения или выделенный слой "Фасад".

Тогда у вас будет только хранилище данных или только доступ к данным, который напрямую заполняет DTO. Я думаю, что часть запросов должна быть оптимизирована для производительности чтения, и в этом случае здесь будут работать прямые запросы/хранимые процедуры в представлениях или таблицах базы данных и SqlDataReaders. Но определенно стоило бы абстрагировать этот доступ за интерфейсом, чтобы впоследствии добавить кэшированную реализацию вниз по треку.

Если вы используете ORM и хотите сопоставить свои объекты домена с DTO, тогда у вас может быть общий QueryRepository, у которого есть методы, которые используют ISpecification или подобную конструкцию для определения ваших запросов, а затем объект DtoAssembler для создания Dtos из объектов домена. Затем реализация имеет объект первого класса для каждого из запросов, которые вы собираетесь выполнять.

Вот довольно надуманный пример, но я надеюсь, что это даст вам представление.

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

Ответ 2

Я думаю, что willbt дал вам действительно хорошую отправную точку.

Я бы добавил, что если вы предпочитаете использовать ORM в качестве стратегии доступа к данным для запросов, вам было бы полезно рассмотреть возможность определения стратегии отбора, с учетом данных, которые, как вы ожидаете, вам нужно будет получить доступ ( Кстати, я думаю конкретно об NHibernate, кстати). Это означает, что вы можете решить, нужно ли ленивать или загружать объекты и коллекции, связанные с конкретным объектом Aggregate Root.

Проект NCommon от Ritesh Rao предлагает отличную (незавершенную работу) демонстрацию того, как определить другую стратегию выбора для разных целей.

Ritesh хорошо объясняет это в своем блоге.

Идем дальше и посмотрим на источник:

В тесте 'Repository_For_Uses_Registered_Fetching_Strategies' вызов

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

... приводит к тому, что стратегии выборки регистрируются по отношению к классу NHRepositoryTests, и поэтому OrderItems и продукты будут загружаться без использования конфигураций сопоставления NHibernate.