В Hibernate-Envers, как сделать более раннюю ревизию сущности последней ревизией - PullRequest
0 голосов
/ 05 сентября 2018

Мое приложение использует Hibernate-Envers 4.3.11

  • Я загружаю музыкальные файлы в свою базу данных с их метаданными (например, названием альбома, исполнителем), представленными как проверенная Песня класс
  • Затем приложение редактирует метаданные по-разному и записывает обратно в класс Song (каждый раз, когда зафиксированный сеанс создает новую ревизию)
  • Затем обычно в конце изменения записываются из текущего класса Song обратно в сам файл.
  • Но при работе в Режим предварительного просмотра в файл ничего не записывается. Поэтому я хочу, чтобы последняя версия класса Song для этого файла теперь содержала те же метаданные, что и версия, созданная при первоначальной загрузке файла.

В настоящее время я делаю это, получая первую ревизию песни и копируя данные, которые она содержит, в последнюю версию песни. но есть ли способ, которым я могу просто сказать: возьми эту более раннюю ревизию и сделай ее самой последней ревизией .

Обновление

Я сейчас реализую ответ Нароса. Так что теперь у меня есть класс с именем SongFile , который всегда представляет содержимое музыкального файла на диске, это @Audited (от Envers), а основным идентификатором является @ GeneratedValue.

Затем у нас есть класс с именем Song , после создания и пропуска сущности SongFile мы создаем эквивалентную сущность Song . Это не проверяется, и основной идентификатор устанавливается вручную, мы устанавливаем primaryId и все метаданные так же, как класс Song.

Затем приложение изменяет метаданные на Песня .

Затем в заключение, если в режиме предварительного просмотра , мы просто сравниваем различия между Song и SongFile и генерируем отчет.

Если в режиме Реальное сохранение мы сравниваем различия между Song и SongFile и генерируем отчет и сохраняем изменения обратно в файл, а SongFile .

Это прекрасно работает и решает ряд проблем.

Однако у меня есть проблема, в музыкальных файлах также могут храниться несколько изображений (в формате JPEG и т. Д.), Мы моделируем их с помощью класса CoverImage , представляющего изображение, и класса CoverArt , который обеспечивает 1: M связь между Song и CoverImage , также хранит атрибут имени.

Теперь проблема в том, что я создал класс CoverArtFile , используемый SongFile , который использует @GeneratedValue и класс CoverArt , используемый Song это не аутоген.

При первоначальной загрузке файла и создании SongFile и Song это работает нормально, копируя автоматически сгенерированное значение из любых CoverArtFile классов в CoverArt class

Однако, если у нас нет coverart для начала, а затем он добавляется приложением, мы терпим неудачу, потому что класс CoverArt не генерирует первичный ключ автоматически, и я не могу безопасно сгенерировать его в случае, если он используется существующий класс CoverArtFile (или будет в будущем).

Если в качестве альтернативы у меня есть CoverArt, использующее автогенерируемое значение, тогда оно не будет таким же, как в связанном с ним классе CoverArtFile.

Как мне поступить?

1 Ответ

0 голосов
/ 05 сентября 2018

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

Так что лучший способ сделать это будет

  1. Получите нужную ревизию из истории аудита, к которой вы хотите вернуться.
  2. Получить существующую сущность из Hibernate.
  3. Установите значения в существующем объекте из (2) с значениями из нужной ревизии, выбранными в (1).
  4. Объединить измененную сущность.

Еще одна идея, которая может сработать, - рассмотреть возможность разделения понятия preview и non-preview . Я имею в виду, что у вас есть две сущности, а не одна Song. У вас есть одна версия, которая представляет собой крайне изменчивую версию для preview , а другая - для менее изменчивой non-preview , предназначенную для представления содержимого файла.

При таком подходе, когда вы изменяете вариант preview , вы просто создаете журнал изменений с Envers для вещей, которые могли быть внесены в файл, но отсутствовали из-за preview-mode . Когда вы изменяете вариант без предварительного просмотра , вы создаете журнал изменений для того, что содержимое файла должно быть .

Предостережение в том, что ваша бизнес-логика должна, вероятно, также синхронизировать вариант preview в этом случае использования, чтобы оба preview и non-preview имели то же самое содержимое, поэтому в основном загрузите сущность preview , измените ее так, чтобы она соответствовала non-preview , а затем сохраните изменения и для нее.

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

* * ОБНОВЛЕНИЕ тысячи сорок-девять

Добавить к моему ответу относительно вашего обновления; именно здесь вы, вероятно, захотите использовать сгенерированные идентификаторы для всех сущностей, и ваши сущности Song и CoverArt сохраняют ссылку либо на проверяемую сущность, либо, по крайней мере, сохраняют значение первичного ключа.

Как пример

@Entity
public class Song {
  @Id
  @GeneratedValue
  private Long id;
  @OneToOne
  private SongFile songFile;      
}

или более просто

@Entity
public class Song {
  @Id
  @GeneratedValue
  private Long id;
  private Long songFileId;
}

Идея состоит в том, что ваши нефайловые сущности поддерживают связь с файловой стороной либо посредством ассоциации (например, @OneToOne), либо хранят идентификатор связанной сущности, чтобы вы могли определить, нужно ли вам выбирать / копировать или построить / вставить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...