2012-07-01 3 views
9

Я нашел проблему с использованием примитивного типа в качестве объекта @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) вместо примитивных типов. Любой сторонний ресурс, описывающий это как рекомендуемую практику, будет очень приятным.

+0

Спасибо за то, что поделились этой информацией с нами. –

+0

Возможный дубликат [Примитив или обертка для первичных ключей спящего режима] (http://stackoverflow.com/questions/3535791/primitive-or-wrapper-for-hibernate-primary-keys) – stevedbrown

ответ

12

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

+1

+1, абсолютно согласен – Raman

0

Я бы использовал тип объекта. В xml-сопоставлении вы можете поместить атрибут «unsaved-value», но я не думаю, что для аннотаций есть прямой перевод. В результате безопаснее придерживаться типов объектов.

И большинство программистов ожидали бы, что значение «null» в идентификаторе будет означать несохранение в любом случае.