Всегда используйте обертки примитивных объектов для JPA @Id вместо примитивного типа?


Я обнаружил проблему с использованием примитивного типа в качестве объекта @Id для JPA в сочетании с Spring Data JPA. У меня есть отношения родитель/ребенок с каскадом.Все на родительской стороне, и у ребенка есть PK, который в то же время является также FK родителя.

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

Проблема заключалась в том, что этот метод Spring Data JPA save () проверяет, является ли сущность новой, и если она новая, то em.persist () используется иначе em.используется функция merge () .

Интересная часть здесь, как весна проверяет, является ли сущность новой или нет:

getId(entity) == null;

И, конечно, это было ложно, потому что я использовал long в качестве типа для @Id, а значение по умолчанию для long равно 0. Когда я поменял long на Long, все работает и с Spring Data JPA.

Так ли это рекомендуется всегда использовать объектные оболочки для примитивных типов (например, Long вместо long) вместо примитивных типов. Любой сторонний ресурс, описывающий это как рекомендуемую практику, был бы очень хорош.

2 10

2 ответа:

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

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

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