Обнаружение изменений в объектах внутри совокупного корневого каталога

StackOverflow https://stackoverflow.com/questions/1421753

Вопрос

Я хочу посмотреть, какие подходы люди могли бы использовать для обнаружения изменений в объектах, которые являются частью их агрегатов.У меня есть кое-что, что работает, но я не в восторге от этого.По сути, мой репозиторий отвечает за определение того, изменилось ли состояние агрегированного корневого каталога.Давайте предположим, что у меня есть совокупный корень, называемый Book и сущность , называемая Page в пределах совокупности.A Book содержит один или несколько Page объекты, хранящиеся в Pages Коллекция.

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

Чтобы облегчить такое поведение для самих объектов, мой EntityBase класс содержит два простых свойства: IsUpdated(), IsDeleted().Оба они по умолчанию имеют значение false.Мне не нужно знать, является ли это новым или нет, потому что я могу сделать это определение на основе наличия ключа, как упоминалось ранее.Методы в реализации, в данном случае на Странице, будут содержать каждый метод, который изменяет набор резервных данных IsUpdated() к истине.

Так, например, у Page есть метод, который называется UpdateSectionName() который изменяет базовое значение SectionName свойство, доступное только для чтения.Этот подход используется последовательно, поскольку он допускает логическую точку привязки средств проверки в методе (предотвращающем переход объекта в недопустимое состояние), который выполняет эту настройку данных.Конечным результатом является то, что я должен поставить this.IsUpdated() = true; в конце метода.

Когда совокупный корневой файл отправляется в репозиторий для Save() (логический переключатель либо на Insert() или Update() операция), затем он может выполнить итерацию по Pages коллекция в Book, ищет любые страницы , на которых есть один из трех сценариев:

  1. Ключа нет.A Page при этом ключ не будет вставлен.
  2. IsDeleted = true; Удаление превосходит обновление, и удаление будет зафиксировано - игнорируя любое обновление для Page.
  3. IsUpdated = true; Для Страницы будет зафиксировано обновление.

Выполнение этого таким образом не позволяет мне просто вслепую обновлять все, что есть в коллекции Pages, что могло бы быть сложной задачей, например, если бы в Книге было несколько сотен страниц.Я подумывал о том, чтобы получить копию Книги, провести сравнение и зафиксировать только обнаруженные изменения (вставки, обновления и удаления на основе присутствия и / или сравнения), но мне показалось, что это ужасно болтливый способ сделать это.

Основным недостатком является то, что разработчик должен помнить о необходимости установки IsUpdated в каждом методе объекта.Забудьте одно из них, и оно не сможет обнаружить изменения для этого значения.Я поиграл с идеей какого-то пользовательского хранилища резервных копий, которое могло бы прозрачно фиксировать изменения во времени, что, в свою очередь, могло бы IsUpdated свойство, доступное только для чтения, которое репозиторий может использовать для агрегирования обновлений.

Репозиторий использует реализацию шаблона unit of work, которая основывает свои действия на временной метке, сгенерированной при добавлении к нему aggregate root.Поскольку в очереди для операций может быть несколько объектов, операции с объектами сворачиваются и выполняются сразу после выполнения агрегированных корневых операций, к которым принадлежат объекты.Я мог бы сделать еще один шаг вперед и создать еще одну единицу работы, чтобы просто обрабатывать операции объекта и основывать их на каком-то отслеживании событий, используемом в объекте (именно поэтому я предполагаю, что некоторые продукты ORM на рынке обладают аналогичным уровнем функциональности).

Однако, прежде чем я продолжу двигаться в этом направлении, я хотел бы услышать идеи / рекомендации / опыт относительно этого.

Редактировать: Несколько дополнительных фрагментов информации, которые было бы полезно знать:

  1. Текущий язык, с которым я работаю, - C #, хотя я старался не раскрывать как можно больше информации, относящейся к конкретному языку, потому что это скорее теоретическое обсуждение.
  2. Код для репозиториев / сервисов/сущностей / и т.д.основан на концепции Тима Маккарти, изложенной в его книге ".NET Domain-Driven Design with C #", и вспомогательном коде на CodePlex ( Кодовый комплекс ).Это обеспечивает доступное понимание используемого подхода, хотя то, с чем я работаю, в значительной степени было переписано с нуля.
Это было полезно?

Решение

Короче говоря, мой ответ заключается в том, что я согласился с тем, что предложил.Это работает, хотя я уверен, что есть возможности для улучшения.Изменения на самом деле заняли очень мало времени, поэтому я чувствую, что в данном случае я не слишком далеко ушел от принципов KISS или YAGNI.:-)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top