Последующее добавление JPA @OrderColumn вызывает нулевой столбец индекса для ошибки сбора

Допустим, у нас есть отношение @OneToMany для сущностей A и B. У каждого A может быть много B.

@Entity
public class A{
  @Id
  private long id;
  ...
  @OneToMany(mappedBy="ref")
  private List<B> items;
  ...
}

@Entity
public class B{
  @Id
  private long id;

  @ManyToOne
  @JoinColumn(name = "A_ID")
  private A ref;
}

Это приложение находится в разработке в течение некоторого времени, и порядок сохранения Б в БД до сих пор не актуален.

Однако теперь требуется точный порядок букв B. Для этого я добавил @OrderColumn, как показано ниже.

@OneToMany
@OrderColumn(name="B_ORDER")
private List<B> items;

Он отлично работает, и в таблице B теперь есть столбец B_ORDER со значениями порядка.

Теперь производственную базу данных необходимо обновить. В таблицу B добавлен новый столбец B_ORDER. Однако для существующих строк этот столбец не имеет значения (null). Когда вы пытаетесь получить список B для уже существующей записи, я получаю следующее исключение:

org.hibernate.HibernateException: null index column for collection

Это нормально иметь список B в любом порядке для старых записей. @OrderColumn имеет свойство nullable, которое по умолчанию равно true. Но это не помогает.

Есть ли способ JPA для этого или я должен сам заполнить эти нулевые значения в db?

Использование JPA 2.1 с Hibernate 4.3.7.


person ilhami visne    schedule 25.05.2016    source источник
comment
Вы нашли лучшее решение для этого, чем упомянутое. В идеале он должен упорядочивать его по идентификатору или чему-то еще или давать случайный список самостоятельно.   -  person Aditya    schedule 04.10.2016
comment
Я не смог попробовать решение, приведенное в ответе ниже, потому что оно пришло через 4 месяца :) (без жалоб, большое спасибо). Мы только что заполнили эти нулевые значения пользовательским скриптом sql. Вы пробовали решение ниже? Если да, то напишите здесь свой опыт.   -  person ilhami visne    schedule 03.04.2017


Ответы (2)


Проблема заключается в том, что поставщику JPA, в вашем случае Hibernate, требуется непрерывное (неразреженное) упорядочение значений столбца порядка.

Однако при добавлении нового столбца в новую базу данных значения будут null, если только вы не определили значение по умолчанию, равное 0.

Вы можете подумать, что добавление значения по умолчанию поможет. Извините, это не так. Если вы это сделаете, в вашей коллекции всегда будет отображаться не более одного предмета.

Чтобы решить эту проблему, вы должны добавить к каждой коллекции последовательную неразреженную нумерацию.

На практике вы должны временно изменить свою сущность, чтобы вы могли получить доступ к соответствующему полю:

@Entity  
public class B{  
@Id  
private long id;  

@ManyToOne  
@JoinColumn(name = "A_ID")  
private A ref; 

@Column(name = "B_ORDER")
private Integer order;
}

Теперь вы можете загрузить все элементы. Далее вам нужно написать временной метод, который загружает все элементы из базы данных и нумерует каждый элемент в коллекции, начиная с 0 и заканчивая длиной коллекции минус 1.

Приведенное выше предложение — это всего лишь один из способов, который я считаю удобным. Есть много способов решить эту проблему. Вы даже можете сделать это вручную, если у вас есть достаточно времени.

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

person Randy    schedule 25.09.2016
comment
Основываясь на приведенном выше описании, это может быть нетривиально для всех: нумерация должна начинаться с 0 для каждого экземпляра A. Другими словами: в таблице базы данных для B для каждого набора строк, который указывает на один и тот же экземпляр A, нумерация должна начинаться с 0. - person Istvan Devai; 18.01.2019

У меня была аналогичная проблема: спящий режим, похоже, не генерировал значения в столбце порядка, когда я обновлял список дочерних элементов для существующего родителя. Я исправил это, явно добавив столбец порядка для дочернего элемента, например (используя ваш пример):

@Entity
public class B{  
  @Column(name = "B_ORDER")
  private int order;

  ...
}

Если бы я этого не сделал, создание A записей с B дочерними элементами работало бы нормально, но обновление A записей путем добавления B дочерних элементов завершилось бы ошибкой с null index column for collection: ..., поскольку спящий режим не генерировал значения. для столбца B_ORDER.

person benterris    schedule 17.05.2021