Hibernate自引用关系和延迟加载

时间:2012-11-14 10:07:58

标签: java hibernate unit-testing jpa lazy-loading

在提出问题之前,这是我的问题的背景:

我有一个名为'Category'的特定实体,它有一个属性Category(父类)和另一个'relatedEntity'类型的属性。

以下是代码示例:

@Entity
public class Category {

    ...

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="entityID")
    private RelatedEntity entity;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="parentID")
    private Category parent;

    ...
}

因此,正如您所看到的,我已经为这些属性声明了ManyToOne关系,并且还为延迟加载提取策略。

现在,我在DAO对象中使用此方法来获取Category:

的列表
public List<Category> getAll() {
    Criteria crit = sessionFactory.getCurrentSession().createCriteria(Category.class);
    return (crit.list());
}

我有一个调用DAO方法的特定服务对象:

@Transactional(readOnly = true)
public List<Category> getAllCategories() {
    return (categoryDAO.getAll());
}

目前没什么特别的......现在,我的单元测试来了:

@Test
public void testCategories() {

    List<Category> cat = service.getAllCategories();
    assertNotNull(cat);
    assertFalse(cat.isEmpty());

    for (Category c : cat) {

        try {
            assertNotNull(c.getEntity().getName());
            fail("Expected lazy init. on Category.Entity");
        }
        catch(LazyInitializationException ex) {
             //Exception is caught
        }

        try {
            assertNotNull(c.getParent().getName());
            //No exception
            fail("Expected lazy init. on Category.Parent");
        }
        catch(LazyInitializationException ex) {}
    }
}

运行测试后,在第一个try / catch块中捕获异常,并触发第二个失败,表示该类别的父属性上没有LazyInitException。

所以我可以打电话给

c.getParent().getParent().getName(); 

c.getParent().getParent().getParent().getName() 

没有任何异常被提出。

我在配置文件中设置了'show_sql = true',在父属性上调用getter之后,我在日志中看不到任何补充请求,因此没有新请求但是父属性已加载。

有人可以解释一下为什么父属性不是懒惰的吗?

编辑:

我已更新我的测试用例。

@Test(expected=LazyInitializationException.class)   
public void lazyCategoriesParentsList() {
    List<Category> cat = service.getAllCategories();

    assertNotNull(cat);
    assertFalse(cat.isEmpty());

    for (Category c : cat) {            
        assertNotNull(c.getParent().getName());     
    }       
}

现在测试正在传递......它与我以前的测试用例中的实体属性(通过c.getEntity())的访问有关吗?

1 个答案:

答案 0 :(得分:2)

你能尝试只获得一个类别而不是全部加载吗?

的确,当您加载类别时,如果hibernate可以在同一个会话中找到,它会初始化它,甚至如果 parent 被标记为懒惰。当您查询所有类别时,它会在会话中找到所有父母并初始化它们。