Hibernate为OneToMany集合

时间:2016-03-23 16:44:11

标签: java hibernate one-to-many hibernate-onetomany

我的问题是,当在以下对象上获取实例时,hibernate会在@OneToMany Set organizationMemberCollection的值中检索 null

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
     */
}

以下是“拥有”该关联的对象:

OrganizationMember.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
     */
}

在这个应用程序中,我们有两种不同的配置:

  • 生产,其中Hibernate连接到PostgreSQL数据库。 这是prod的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>

  • 测试,其中Hibernate被连接到内存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的doc进行了几个小时的研究之后,我仍然没有发现任何与同一问题/行为有关的帖子,所以我会失去一点点帮助,非常感谢你的帮助!

如果需要,我当然可以提供更多信息,谢谢!

编辑:

测试高亮问题:

@Test
@Transactional
public void testFindUserAccount_OrganizationMemberCollectionFetching() {

    assertNotNull(userAccountDao.findUserAccount("user1@test.fr"));  //NoProblem
    assertNotNull(userAccountDao.findUserAccount("user1@test.fr").getCabinetMemberCollection());  //Fails

}

使用以下findUserAccount dao

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;
    }
}

3 个答案:

答案 0 :(得分:5)

问题是数据库填充和测试是在同一个事务中运行的,并且在这两个步骤之间没有清理hibernate缓存。

结果是hibernate并没有真正将请求发送到数据库,而是点击了缓存并返回了对象而没有与映射关系进行任何连接。

可能的解决方案是:

  • 在不同的交易中填充数据库。
  • 在人口之后清理会话SessionFactory.getCurrentSession().flush();。 (如果需要,请冲洗会话:null)。

每种可能性都会强制下一个查询真正命中数据库,因此连接将发生,映射的Collection将包含所需数据(如果连接没有结果,则为空,但无论如何,Collection赢了#39 ; t具有using Microsoft.Data.Entity; 值。

在我看来,第一种解决方案更好,因为如果测试中出现问题,它不能回滚整个人口。

答案 1 :(得分:1)

它是一个延迟加载的集合,所以hibernate没有做任何事情来初始化它,这很正常hibernate在这里返回null ..

我通常做的是在属性上声明一个空的HashSet

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

答案 2 :(得分:0)

就我而言,这是因为我有“瞬态”,因为实体不可序列化,声纳告诉我添加瞬态关键字

@OneToMany(mappedBy = "message", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY)
    private transient List<UserReadSystemMessage> usersRead;

注意瞬态