Я нашел проблему с использованием примитивного типа в качестве объекта @Id для JPA в сочетании с Spring Data JPA. У меня есть родительские/дочерние отношения с Cascade.ALL на родительской стороне, а у ребенка есть PK, который в то же время является также FK родителя.Всегда используйте примитивные обертки объектов для JPA @Id вместо примитивного типа?
class Parent {
@Id
private long id;
@OneToOne(mappedBy = "parent", cascade = ALL)
private Child child;
}
class Child {
@Id
@OneToOne
private Parent parent;
}
Так что, когда я бегу:
...
Parent parent = new Parent();
Child child = new Child(parent);
parent.setChild(child);
em.persist(parent)
...
все работает отлично. Но я использовал Spring Data JPA сохраняться объект, поэтому я бегу вместо:
parentRepository.save(parent); // instead of em.persist(parent);
и этот один был не удалось за исключением следующего:
Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Parent
Проблема заключалась в том, что JPA Spring Data сохранить () метод проверяет, является ли объект новым, а если он новый, то em.persist() используется иначе em.merge() используется.
Самое интересное здесь, как Spring проверяет, является ли объект новым или нет:
getId(entity) == null;
И, конечно, это было ложным, потому что я давно в качестве типа @Id, и значение по умолчанию for long равно 0. Когда я долго менял Long, все работает с Spring Data JPA.
Так рекомендуется всегда использовать обертки объектов для примитивных типов (например, Long вместо long) вместо примитивных типов. Любой сторонний ресурс, описывающий это как рекомендуемую практику, будет очень приятным.
Спасибо за то, что поделились этой информацией с нами. –
Возможный дубликат [Примитив или обертка для первичных ключей спящего режима] (http://stackoverflow.com/questions/3535791/primitive-or-wrapper-for-hibernate-primary-keys) – stevedbrown