2009-05-26 3 views
3

[Edit: Судя по всему, это только вопрос для массивов и ответ FoxyBOA в может направить (или даже есть) ответ.]Почему связанные коллекции содержат нулевые значения? (Hibernate, аннотация, весна)

Мой вопрос связан с этим программным обеспечением: Hibernate3 + аннотаций , Spring MVC, MySQL и в этом примере также Spring Security.

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

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

@OneToMany 
@JoinColumn(name = "username") 
@IndexColumn(name="id") // "id" was the primary key and is used to sort the elements 
public Authority[] getAuthorities() { 
    return authorities; 
} 
public void setAuthorities(Authority[] authorities) { 
    this.authorities = authorities; 
} 

... Я в конечном итоге с коллекцией «власти», содержащий 14 (0-13) элементы из которых только четыре не являются нулевыми (четыре строки в таблице базы данных принадлежат этому конкретному пользователю, так что это правильно). Насколько я понимаю, я использую Hibernate по умолчанию для свойства, как Fetchmode и т.д. я получаю пользователь так:

Criteria criteria = getSession().createCriteria(User.class); 
criteria.add(Restrictions.eq("username",username)); 
User user = (User) criteria.uniqueResult(); 

каротажную информация из org.hibernate.loader.loader правильно «упоминает» четыре строки для результат. Тем не менее, созданный пользователь имеет четыре правильных элемента плюс десять нулевых значений в массиве. В моем конкретном примере это приводит к этому исключению:

java.lang.IllegalArgumentException: Granted authority element 0 is null - GrantedAuthority[] cannot contain any null elements 

ответ

2

Я могу порекомендовать вам проверить ваши данные. Если у вас есть пропущенные индексы (столбец идентификаторов в вашем случае), то вместо пропущенного id вы получите нуль в своем массиве. I.e.

table authorities: 
username id 
bob 1 
bob 3 
bob 5 

В результате вы будете иметь массив: {0 = нуль, 1 = ЛПП, 2 = нуль, 3 = ЛПП, 4 = NULL, 5 = боб}

ОБНОВЛЕНИЕ: я встретил ситуацию в двух случаях:

  1. Пропущенные ключевые значения в индексированный столбец ид в власти таблицы (например, 0,1,3,4,5 - отсутствует значение 2. будет Hibernate авто математически добавить значение массива с ключом 2 и значением null).
  2. Индексированные значения в порядке, но некоторые критерии фильтруют часть из них (например, ваш HQL, подобный тому, что «от пользователя u присоединяется к u.authorities a, где a.id = 2». В этом случае спящий режим загружает пользователя, но в массив полномочий у вас будет только 3 значения: 0 - null, 1 - null, 2 - полномочия с id 2).
+0

Я добавил и удалил некоторые индексы, но по-прежнему получаю 14 значений с четырьмя правильными значениями в тех индексах массива, которые совпадают с значением в моем столбце id. Поэтому я действительно думаю, что это моя проблема. Не могли бы вы «разработать» немного больше, я не совсем понимаю, что вы имеете в виду. Спасибо, пока! – Wolfram

3

Ответ лежит в аннотации @IndexColumn. В качестве индекса массива используется значение id, поэтому количество элементов в массиве в основном будет значением самого высокого идентификатора в таблице «Власти».

см hibernate documentation on indexed collections

попробуйте удалить аннотацию.

Также как мысль; вы рассматривали использование набора для сопоставления? это не является строго необходимым, это всего лишь немного более распространенная форма картографирования, и это все.

+0

Во-первых, у меня не было аннотации @IndexColumn, в результате чего «org.hibernate.AnnotationException: List/array должен быть аннотирован с помощью @IndexColumn». Что касается вопроса типа: я реализовал интерфейс UserDetails и его метод «GrantedAuthority [] getAuthorities();». Я рассмотрю это, чтобы избавиться от @IndexColumn. Вы действительно помогли мне понять эту проблему. – Wolfram

+0

Я вижу. Я реализовал интеграцию с весной безопасности несколько раз, шаблон, который мне больше всего понравился, - это использовать метод UserDetails toUserDetails() для объекта User. Это позволяет использовать неизменяемую реализацию без спящего режима, которая, в свою очередь, хорошо вам подойдет, если положить hibernate-объекты в сеанс http (так как большинство пользовательских деталей в конечном итоге) почти всегда заканчивается слезами. –

+0

Звучит здорово. И вместо того, чтобы возвращать пользователя непосредственно из метода loadUserByUsername (..) "UserDetailsService, вы возвращаете user.toUserDetails()? Что касается «конца в слезах», когда я исправлял массив вручную, я оказался в многочисленных исключениях Hibernate (например, при попытке записать нулевого пользователя обратно в БД, откуда бы я ни пришел, это еще больше, но «откат» к моей первой проблеме). Наверное, это то, что вы имели в виду. – Wolfram

Смежные вопросы