Я работаю над кодом, который позволяет переносить граф объектов из одной базы данных в другую. Граф объектов представляет конфигурацию, мы по существу перемещаем конфигурацию из промежуточной среды в производственную среду.
График извлекается из исходной БД, отсоединяется, сериализуется, а затем объединяется с целевой БД.
Пока это работает очень хорошо, но у меня есть один рассол.
У меня есть график, который выглядит так:
@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 могут помочь, но я не понимаю, как это сделать.