Hibernate не позволяет встроенному объекту с полем int быть нулевым?

Hibernate не позволяет мне сохранять объект, содержащий нулевой внедренный объект с целым полем. Например, если у меня есть класс под названием Thing, который выглядит так:

@Entity
public class Thing {

    @Id
    public String id;

    public Part part;

}

где Part является вложенным классом, который выглядит следующим образом

@Embeddable
public class Part {

    public String a;    

    public int b;

}

а затем пытается сохранить объект Thing с нулевой частью, вызывает Hibernate, чтобы выбросить исключение. В частности, этот код

Thing th = new Thing();
th.id = "thing.1";
th.part = null;
session.saveOrUpdate(th);

заставляет Hibernate выбрасывать это исключение

org.hibernate.PropertyValueException: not-null property references a null or transient value: com.ace.moab.api.jobs.Thing.part

Я предполагаю, что это происходит потому, что Part является встроенным классом, поэтому Part.a и Part.b являются просто столбцами в таблице базы Thing. Поскольку Thing.part является нулевым, Hibernate хочет установить значения столбца Part.a и Part.b равными null для строки для thing.1. Тем не менее, Part.b является целым числом, а Hibernate не допускает значения целых столбцов в базе данных. Это то, что вызывает исключение, правильно?

Итак, я ищу обходные пути для этой проблемы. Я заметил, что сделать Part.b целым, а не int, кажется, работает, но по причинам, которые я не буду вас беспокоить, это не очень хороший вариант для нас. Спасибо!

Ответ 1

Я нашел другое обходное решение и подумал, что поделюсь им. Оказывается, что если вы делаете int column nullable, то Hibernate не бросает PropertyValueException.

@Column(nullable = true)
public Integer b;

Это работает для нас, потому что наше приложение с включенной поддержкой гибернации - это единственное, что касалось базы данных, и поэтому мы можем гарантировать, что b является нулевым, только если эта часть равна нулю. Хотя предложение нулевой части и использование типа обертки Integer являются отличными предложениями, из-за множества причин, на которые я действительно не контролирую, установка столбца на nullable лучше всего подходит для нас. Спасибо, хотя и надеюсь, что это поможет кому-то другому.

Ответ 2

Довольно неудобно, да. Вы можете установить значение по умолчанию в поле part:

private Part part = new Part();

или даже

private Part part = Part.NULL_PART;

(см. Отверстие нулевого объекта)

Имейте в виду, что если ваш класс @Embeddable не содержит примитив (который имеет значение по умолчанию), и вы сохраняете объект со всеми null s, вся структура будет сохраняться в базе данных как null, потому что для hibernate нет возможности внести изменения в базу данных, нет ли у вас объекта или нет пустого. Чтобы обойти это, если это возникнет, вам нужно создать фиктивное поле (лучше всего boolean).

Ответ 3

Вы абсолютно правы в том, что происходит. Когда объект встроенного класса имеет значение null, Hibernate представляет это, делая все его столбцы нулевыми в базе данных; к сожалению, это означает, что Hibernate не может определить разницу между нулевым встраиваемым объектом и вложенным объектом со всеми нулевыми значениями.

Насколько я знаю, если вы не можете сделать поле нулевым (сделав его Integer, как вы догадались), единственный способ создать собственный тип Hibernate. Должно быть выполнимо, но это будет больно сделать так. На самом деле, вероятно, это будет хуже, чем любая причина, по которой вы не можете использовать Integer - так в чем же причина?

Ответ 4

Везде, где возможно, используйте классы Wrapper (Integer, Long, Double...): особенно, если вам нужно привязать столбец или 2 к существующей таблице. Автобокс твой друг.