2011-06-23 38 views
1

我有2点简单的模型:不匹配HQL结果左Hibernate的标准API的结果连接抓取

class Parent { 
    Long id; //auto generated sequence and primary key 
    String name; 
    Set<Child> children; 
} 

class Child { 
    String name; 
    Long parent_id; //foreign key 
} 

我有一个HQL这样的查询:

FROM Parent p 
    left join fetch p.children as children 
WHERE p.name = 'John' 

'孩子' 是一个集合(在Parent模型中设置'Child'模型。

如果'John'有2个孩子,通过执行单个查询,上面查询的结果给出了每个有2个孩子的2个父母(相同引用)的列表。

我想实现通过标准API同象下面这样:

Criteria c = session.createCriteria(Parent.class); 
c.setFetchMode("children", FetchMode.JOIN); 
c.createCriteria("children", Criteria.LEFT_JOIN); 
c.add(Restrictions.eq("name", "John")); 
c.scroll(); 

有了上面的代码中,我得到2个父实例(同一基准)的列表中,只有1名儿童元素(而不是预期的2 )bu执行单个sql查询。

我在做什么错误的API?当我看到生成的sql时,它是一样的。

+0

看起来这与'c.scroll()'和'c.list()'有关,而不是HQL和Criteria API之间的区别。当我发布这个问题时,我使用'query.list()'作为HQL,'c.scroll()'作为Criteria API。现在我尝试了所有4种组合,发现只有c.scroll()以意想不到的方式行事。我不明白为什么或如何解决它。 – Bhargava

+0

看起来在'scroll'期间,'session'只查看缓存中的父标识符,而没有用新的子关联来更新它。但是'list'似乎正在用新的子关联更新缓存的父对象。我的推理是,它不希望为同一个对象提供2种不同的状态,因此如果在进一步滚动期间再次遇到缓存对象,它不会更新缓存对象。我对吗?我试过'c.setCacheable(false)'/'c.setCacheable(true); c.setCacheMode(CacheMode.IGNORE/REFRESH)'但不起作用。 – Bhargava

+0

它看起来像我需要滚动有序的父列表和订购与2查询的子列表,他们合并它们programmatic-ally冬眠外。我想知道是否有更好的方法。 – Bhargava

回答

0

我有类似的情况,在这里是等价(在我的处境至少)代码:

Criteria c = session.createCriteria(Parent.class); 
c.setFetchMode("children", FetchMode.JOIN); 
c.add(Restrictions.eq("name", "John")); 

List<Parent> list = c.list(); 
Iterator<Parent> iter = list.iterator(); 

我的印象中,行 c.scroll();强制相似的行为c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

+0

其实,那不是我所观察到的。如果应用了'DISTRINCT_ROOT_ENTITY'变形器,'c.list()'返回一个具有2个子元素的父列表实例。 'c.scroll()'完全不受这个结果转换器的影响。 – Bhargava

+0

此外,我看到你的代码没有指定一个左连接,我猜测默认情况下自然连接是通过休眠来选择的。 – Bhargava

+0

给出一个一对多的关系,左外连接是我在设置'FetchMode.JOIN'时观察到的默认行为 – iliaden

1

我有同样的问题,并通过Hibernate代码调试后,我认为这是一个Hibernate的错误,而不是你做错的任何事情。

它被修复为this Hibernate issue,但我们的Criteria仍然在可滚动结果中返回不完整的子集合。我发现在Loader类中有一些逻辑决定是否使用FetchingScrollableResultsImpl来正确处理行,而在CriteriaLoader上它从来没有这样做,因为needsFetchingScroll()总是返回false。然而QueryLoader确实在使用联合抓取时使用它,这就是为什么将我们的Criteria转换为HQL解决了我们的问题。

我打算提交一个Hibernate的bug来实现CriteriaLoader.needsFetchingScroll()