2016-03-23 5 views
3

Моя проблема заключается в том, что спящий режим извлечения нуль в значении @OneToMany Set organizationMemberCollection при извлечении экземпляра по объекту:Hibernate получить нуль для сбора OneToMany

UserAccount.java:

@Entity 
@Table(name="USER_ACCOUNT") 
public class UserAccount { 

    @Id 
    @Column(name = "id", nullable = false) 
    @SequenceGenerator(name = "generator", sequenceName = "USER_ACCOUNT_id_seq", allocationSize=1) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator") 
    private Long id; 

    @Column(name = "EMAIL", nullable = false) 
    private String email; 

    @Column(name = "PASSWORD_HASH") 
    private String passwordHash; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "userAccount") 
    private Set <OrganizationMember> organizationMemberCollection; 

    ... 

    /* 
    * getters and setters 
    */ 
} 

Вот объект, который «владеет» ассоциацией:

ОрганизацияMember.java:

@Entity 
@Table(name="ORGANIZATION_MEMBER") 
public class OrganizationMember{ 

    @Id 
    @Column(name = "id", nullable = false) 
    @SequenceGenerator(name = "generator", sequenceName = "ORGANIZATION_MEMBER_id_seq", allocationSize=1) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator") 
    private Long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "USER_ACCOUNT_ID", nullable = false) 
    private UserAccount userAccount;  

    ... 

    /* 
    * getters and setters 
    */ 
} 

В этом приложении мы имеем два различных configuations:

  • Производство, где Hibernate подключается к базе данных PostgreSQL. Вот SessionFactory конфигурация для прод:

    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="hibernateProperties"> <props> <prop key="hibernate.jdbc.batch_size">10</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cglib.use_reflection_optimizer">false</prop> </props> </property> ... </bean>

  • Test, где Hibernate является conencted Ань в памяти базы данных HSQLDB:

    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.cglib.use_reflection_optimizer">false</prop> <prop key="hibernate.hbm2ddl.auto">create-drop</prop> <prop key="hibernate.cache.use_second_level_cache">false</prop> <prop key="hibernate.cache.use_query_cache">false</prop> </props> </property> ... </bean>

Этот вопрос только показать в конфигурации тестирования; В производственной конфигурации все идет хорошо, и я могу получить коллекцию. Однако, когда я получаю UserAccount в тестовой конфигурации, я получаю null в свойстве organizationMemberCollection (Не пустой набор).

После нескольких часов исследований с помощью документов google и Hibernate я до сих пор не нашел сообщений, связанных с одной и той же проблемой/поведением, поэтому я потерял битлу, и помощь будет принята с благодарностью!

Я могу, конечно, предоставить дополнительную информацию, если это необходимо, спасибо!

Edit:

Тест higlighting проблему:

@Test 
@Transactional 
public void testFindUserAccount_OrganizationMemberCollectionFetching() { 

    assertNotNull(userAccountDao.findUserAccount("[email protected]")); //NoProblem 
    assertNotNull(userAccountDao.findUserAccount("[email protected]").getCabinetMemberCollection()); //Fails 

} 

Со следующим findUserAccount дао

public UserAccount findUserAccount(String email) { 
    if (email == null) { 
     return null; 
    } 
    UserAccount userAccount = (UserAccount) this.sessionFactory 
      .getCurrentSession().createCriteria(UserAccount.class) 
      .add(Restrictions.eq("email", email).ignoreCase()) 
      .uniqueResult(); 
    if (userAccount == null) { 
     throw new ObjectNotFoundException("UserAccount.notFound"); 
    } else { 
     return userAccount; 
    } 
} 
+0

вы получаете нуль, потому что у вас нет какой-либо организацииMemberCollection, связанной с вашим userAccount. Можете ли вы предоставить код вашего теста? возможно, вы забыли вызвать метод setUserAccount перед сохранением объекта OrganizationMember –

+0

Спасибо за быстрый ответ, я думаю, что в такой ситуации Hibernate вернет мой UserAccount с пустым Set, а не с нулевым значением, но, возможно, я ошибаюсь. Я уверен, что у OrganizationMember есть ссылка на учетную запись пользователя, потому что db заполняется перед тестами. И когда я получаю объект OrganizationMember, объект, возвращаемый спящим режимом, имеет ссылку на UserAccount. – Tom

+0

Вы уверены, что контекст персистентности не близок, когда вы вызываете getOrganizationMemberCollection в своем тесте? Если бы мы могли видеть код, возможно, это могло бы помочь –

ответ

4

Проблема в том, что население базы данных и испытания были запущен в той же транзакции, и спящий режим кэш не был очищен от этих двух шагов ,

Последствием этого было то, что спящий режим действительно не уволил запрос в базу данных, но вместо этого ударил кеш и возвратил объект без какого-либо соединения с сопоставленным отношением.

Возможные решения:

  • Заполняем базу данных в другой транзакции.
  • Очистить сеанс SessionFactory.getCurrentSession().clean(); после населения. (Сначала очистите сеанс, если необходимо: SessionFactory.getCurrentSession().flush();).

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

В моем мнении первое решение намного лучше, поскольку оно не откатывает всю популяцию, если что-то пойдет не так в тесте.

0

Это лениво загрузится коллекция, поэтому спящий режим не делает ничего, чтобы инициализировать его , вполне нормально, что спящий режим возвращается null здесь.

То, что я обычно делаю это объявить пустой HashSet на имущество:

@OneToMany(fetch = FetchType.LAZY, mappedBy = "userAccount") 
private Set <OrganizationMember> organizationMemberCollection = new hashSet<>(); 
+0

Спасибо за ваш ответ, я считаю, что FetchType.LAZY означает, что спящий режим будет инициализировать мою коллекцию прокси-сервером в моей коллекции, а не нулевой указатель. – Tom

+0

На самом деле нет ... что '= new hashSet <>();' говорит hibernate инициализировать прокси-сервер ... не FetchType.LAZY – Pras

+0

Попытка решить NPE, но полученный Set пуст, похоже, что hibernate не признать это сопоставление. Я до сих пор не понимаю, почему он работает с реальной базой данных, но не в базе данных в памяти. – Tom

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

  • Нет связанных вопросов^_^