EclipseLink сохранение новых объектов в отношениях ManyToOne даже при отсутствии каскада.СОХРАНЯЕТСЯ

#jpa #eclipselink

#jpa #eclipselink

Вопрос:

У меня такая ситуация

 public class A {

    @ManyToOne(cascade = { CascadeType.REFRESH })
    @JoinColumn(name = "COLUMN_B_ID", insertable = false, updatable = false)
    private B testB;

}
  

Я бы подумал, что независимо от того, какие изменения внесены в свойство TestB в классе A, оно не будет сохранено. Однако, когда я делаю следующее

 A testA = new A();
a.setTestB(new B());
save(testA);
  

EclipseLink сначала пытается сохранить TestB, прежде чем сохранять testA. Я бы подумал, что, поскольку сопоставление ManyToOne в TestB не установлено в CascadeType.СОХРАНЯЕТСЯ, и поскольку insertable и updateable имеют значения false, любая попытка установить новый экземпляр B в A не сработала бы при сохранении A, но я вижу обратное. Есть идеи, что может быть не так? Есть ли способ предотвратить это?

Ответ №1:

Я тестирую приведенный ниже код на Eclipselink 2.2.1, и он выдает исключение, требующее CascadeType.PERSIST присутствия:

 Caused by: java.lang.IllegalStateException: During synchronization a new object
was found through a relationship that was not marked cascade PERSIST: eclipselin
k.saving.neww.objects.in.manytoone.relationship.even.when.no.cascade.B@109f188a.
  

С Eclipselink 2.5.1 возникает то же исключение:

 Caused by: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: test.B@6db66c18.
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:310)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:723)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1516)
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)
  
 A a = new A();
a.setTestB(new B());
em.persist(a);
  

Комментарии:

1. Это интересно, спасибо за проверку. Я использую EclipseLink 2.5.1. Является ли это изменением в поведении? У вас есть полная трассировка, чтобы я мог проверить класс?

2. Опубликуйте всю реализацию A и B и как вы ее «сохраняете», потому что вы передаете экземпляр какому-то магическому методу save . Базовый уровень — просто опубликуйте больше кода.

3. Спасибо за тестирование этого. Мне сложнее вставить все методы, которые вызываются для сохранения, поскольку это одна небольшая часть корпоративного приложения. Однако, основываясь на вашем открытии, я создал небольшой проект JPA и попытался выполнить то, что я опубликовал ранее, и я получил трассировку стека, которую вы тоже сделали. Итак, по сути, на мой вопрос получен ответ, что JPA хочет, чтобы вы установили Cascade. Тип = СОХРАНЯЕТСЯ, когда вы устанавливаете новые объекты подобным образом. Теперь мне нужно выяснить, почему в моем приложении entity этот STE не отображается, но EclipseLink продолжает работу и сохраняется. Большое спасибо. Я сообщу обо всем, что найду.

4. Хорошо, я думаю, я понял, что происходит. В нашем приложении вызывается не em.persist(a), а em.merge(a). По-видимому, поведение отличается для двух. Первый выдает STE, но второй автоматически создает объект B, а затем сохраняет объект A. Я не знаю, является ли это частью спецификаций JPA, я новичок, но это мое наблюдение.

5. Кто-нибудь знает, является ли это другое поведение при слиянии частью спецификаций EclipseLink или это ошибка? Для меня это звучит как ошибка, что операция слияния игнорирует настройки каскада и не предупреждает пользователя об этом.