2013-11-13 3 views
3

У меня есть приложение, которое управляет билетами и клиентами. Клиенту принадлежит много билетов. Если клиент удален, так же как и его билеты. Это один из тестов, чтобы увидеть, должен ли объект быть агрегатом или нет. Я выбрал, что они должны быть объектами не под совокупным корнем. Я обычно загружу и покажу список билетов, охватывающих многих клиентов. Я использую SQL Server для сохранения данных в реляционном формате.От CRUD до DDD

Моя архитектура является следующее:

  1. ASP.NET MVC приложение.
  2. Служба WCF (фасад). Эта служба имеет общедоступные методы, такие как GetTicket, GetTickets, GetCustomer и GetCustomers. Для этого он использует репозитории. Он также имеет открытый метод Run. Run принимает команду, которая может быть AssignTicket, ChangeTicketName и т. Д. Для обработки команд на фасад вводятся службы, ITicketService и ICustomerService. Методы этих служб используются для выполнения команд с фасада. Для загрузки данных службы используют ITicketRepository и ICustomerRepository.
  3. связи базы данных SQL Server

Я получаю вешал на сохранение ссылок из билетов клиентов. Реляционно, у Билета есть FK, который сопоставляется с таблицей Customers. Когда пользовательский интерфейс просматривает индивидуальный билет, он вызывает Facade.GetTicket (id) и Facade.GetCustomers(). Я могу отобразить все данные о билете и имя клиента, к которому он принадлежит. Все в порядке и денди. Но как насчет большого списка билетов, принадлежащих многим другим клиентам. Помните, что в Ticket содержится только Guid, который ссылается на клиента. Я не хочу, чтобы нужно было вызвать фасад, чтобы получить имя клиента для каждого отдельного билета, который я собираюсь перечислить в пользовательском интерфейсе. Действительно ли для моих билетов есть объект значений CustomerInfo (CustomerId и CustomerName) на них? Можно ли использовать оператор sql для объединения этих данных? Что делать, если я не использовал реляционный db? Как изменится имя клиента? В системе Ticket фактически содержит ссылки на несколько других объектов.

Похоже, что в бизнес-логике DDD есть разъединение и что должен отображать пользовательский интерфейс.

ответ

16

Если клиент удален, то есть его билеты. Это один из тестов, чтобы увидеть, должен ли объект быть агрегатом или нет.

Я бы не ожидал, что ваши эксперты в области говорят, что они «удаляют клиентов». Клиенты могут быть заблокированы, или их Аккаунт приостановлен, Билеты могут быть отменены или перенесены, но сам термин «удалить» очень CRUD-ориентирован. В идеале вы никогда не должны постоянно удалять данные (вы могли бы заархивировать его в другом хранилище данных, возможно,?), А каскадные удаления IMHO - опасный ход. Пусть ваш ORM справится с этим.

Определение совокупности - это определение границы консистенции, в которой состояние агрегата является «правильным» в соответствии с инвариантами, определенными для этой совокупности экспертами домена. Так вы определяете границу агрегата.

Я получаю вешал на сохранение ссылок из билетов клиентов

быть ясно, что есть разница между моделью домена, в котором Сущность и ценностные объекты собраны в агрегаты, и моделями данных , который на самом деле является лишь кодовым представлением вашей базы данных на выбранном языке ООП.Ваша модель данных - это ваши таблицы, а может быть совершенно другой формой для вашей модели домена. Ваша модель данных может иметь отношения между таблицами, где фактическая ссылка не существует. Другими словами, вы можете иметь ссылки на внешние ключи по совокупным границам. Это только для обеспечения ссылочной целостности в базе данных. Если вы должны использовать ORM для сопоставления этих таблиц с классами, у вас не будет «свойств навигации», а только значений идентификатора.

Похоже, что в бизнес-логике DDD есть разъединение и что должен отображать пользовательский интерфейс.

Теперь мы начинаем говорить о CQRS. DDD представляет собой моделирование поведения в вашей проблемной области. У модели домена должно быть много поведения (и, возможно, нет публичного состояния, к которому я приступлю). При вызове логики домена вы должны в одной транзакции загружать агрегат, вызывать требуемое поведение и сохранять результат. Поэтому Ваше хранилище должно выглядеть примерно так:

public interface IRepository<TEntity> 
{ 
    TEntity Get(Guid id); 
    void Save(TEntity item); 
} 

Реализация будет всегда жадно нагрузки все, потому что в вашем отображении ОРМА вы не включили ссылки на лицо, не входящих в совокупности. На самом деле, вы уже можете подумать, что база данных документов лучше подходит для хранения агрегатов, и ИМХО вы были бы правы.

Но как вы тогда запрашиваете? Легко. Напишите запрос. Если вы внедряете CQRS, у вас есть тонкий уровень чтения, который НЕ ДЕЛАЕТ, используйте ваш репозиторий, а НЕ ДЕЛАЕТ использовать ваши тщательно обработанные объекты и их ORM-сопоставления. Просто напишите запрос. Если вы используете SQL Server, подумайте о том, чтобы скомбинировать сверхбыстрый Linq to SQL data context или использовать Dapper или Simple.Data. Или даже просто ADO.NET. Дело в том, что ваши запросы касаются получения некоторых данных из базы данных, и для этого вам не нужно поведение.

Если вы используете базу данных документов для своей совокупной персистентности, то разумная реализация шаблона CQRS может увидеть, что вы, возможно, создаете полностью отдельную базу данных, используя события, созданные из поведения домена. Варианты этого «Read Store» бесконечны. Вот некоторые идеи:

  • То же или другой экземпляр документа db, но с предварительно построенными режимами просмотра.
  • База данных SQL (вы можете отказаться от 3-й нормальной формы и пойти с дублированием, так как вы хотите оптимизировать производительность чтения, а не производительность OLTP).
  • Предварительно написанные файлы HTML на диске?

Bonus чат (Event Sourcing)

Предполагая, что вы идете для подхода с использованием события из вашего домена, чтобы построить магазин пользователя, доступ к которому с Thin Read Layer в приложении (дон 't потрудитесь с репозиториями или массивными структурами ORM. Используйте немного Dapper или что-то простое), как вы убедитесь, что у вас всегда есть правильные события с нужными данными в них? Что ж, что, если вы на самом деле никогда не хранили сами агрегаты? Что делать, если вы сохранили события, генерируемые агрегатами в хранилище событий, с потоком событий для агрегата? Когда вы хотите загрузить агрегат, вы загружаете его события и воспроизводите их в памяти, чтобы создать до последнего состояния агрегата.

Я больше не буду вдаваться в это, но стоит исследовать CQRS и Event Sourcing, поскольку они отличные друзья с DDD и хорошо сочетаются друг с другом. :)

+0

«Будьте ясны, что существует разница между моделью домена, в которой объекты и объекты ценности собраны в агрегаты». - Между моделью домена и что? –

+0

Хорошее место - я имел в виду между моделью домена и моделью данных. Исправлено в сообщении. –

+0

Я понял, что вы имели в виду, но просто чтобы быть ясным. –

Смежные вопросы