Установка границ для слияния JPA () - PullRequest
1 голос
/ 29 февраля 2012

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

График извлекается из исходной БД, отсоединяется, сериализуется, а затем объединяется с целевой БД.

Пока это работает очень хорошо, но у меня есть один рассол.

У меня есть график, который выглядит так:

@Entity
class UoObject
{
  @Id
  private int uoObject;

  @OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
  private Set<UoAttribute> uoAttribute;

  // Other irrelevant fields
}

@Entity
class UoAttribute
{
  @Id
  private int uoAttribute;

  @OneToOne(optional=true, fetch=FetchType.EAGER, cascade=CascadeType.ALL)
  private UoAttributeObject uoAttributeObject;

}

@Entity
class UoAttributeObject
{
  @Id
  private UoAttribute uoAttribute;

  @ManyToOne
  private UoObject uoObject;
}

Так что здесь UoObject имеет коллекцию UoAttributes, и эти UoAttributes могут иметь UoAttributeObject, который ссылается на другой UoObject.

Предполагается, что UoObjects, на которые ссылаются UoAttributeObjects, уже находятся в целевой базе данных. Если это не так, я хочу поднять ошибку. Для ясности я никогда не хочу, чтобы целевой объект UoObject обновлял свое состояние ... по сути, я хочу установить только отношения.

Когда я это реализовал, я ожидал, что без каскада = MERGE в отношениях JPA выдаст ошибку, говорящую о том, что объект не существует. Или даже уровень базы данных в конечном итоге будет жаловаться на внешние ключи. Вместо этого я обнаружил, что JPA пытается вставить в основном пустой экземпляр UoObject (установлен только ключ). Я нашел это в спецификации JPA 2.0:

Если X является объектом, объединенным с X ', со ссылкой на другой объект Y, где не указан cascade = MERGE или cascade = ALL, то навигация по той же ассоциации из X' дает ссылку на управляемый объект Y 'с той же настойчивой идентичностью, что и Y.

Кажется, что исходная БД обнаруживает, что целевой UoObject не существует, планирует экземпляр для вставки (плохо), но не объединяет состояние исходного UoObject с (хорошо!).

В исходной стороне БД, есть ли способ, которым я могу обнаружить, что объект уже не был в БД, и вызвать ошибку? Я подозреваю, что обратные вызовы жизненного цикла @PrePersist и @PreUpdate могут помочь, но я не понимаю, как это сделать.

1 Ответ

0 голосов
/ 29 февраля 2012

Что произойдет, если вы добавите @Version к UoObject?

По сути, вы объединяете поврежденный граф объектов, поэтому результат может быть трудно определить.Использование блокировки может помочь в этих ситуациях.По сути, вы можете посмотреть на это, когда вы объединяете изменения из одной транзакции (вашей старой базы данных) и имеете несовместимое состояние (поскольку объект был удален в новой базе данных в другой транзакции), поэтому единственный способ решить такие проблемы параллелизма - этоБлокировка.

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

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

...