Hibernate Criteria使用FetchType.EAGER多次返回子项 [英] Hibernate Criteria returns children multiple times with FetchType.EAGER

查看:93
本文介绍了Hibernate Criteria使用FetchType.EAGER多次返回子项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Order 类,它有一个 OrderTransactions 的列表,许多Hibernate映射如下:

  @OneToMany(targetEntity = OrderTransaction.class,cascade = CascadeType.ALL)
public列表与LT; OrderTransaction> getOrderTransactions(){
return orderTransactions;

这些订单 s还有一个字段 orderStatus ,它用于使用以下标准进行过滤:

  public List< Order> getOrderForProduct(OrderFilter orderFilter){
Criteria criteria = getHibernateSession()
.createCriteria(Order.class)
.add(Restrictions.in(orderStatus,orderFilter.getStatusesToShow()));
return criteria.list();
}

这样做的效果和预期的一样。



现在这里是我的问题:为什么当我明确设置获取类型为 EAGER 时,请执行 Order s在结果列表中多次出现?

  @OneToMany(targetEntity = OrderTransaction.class,fetch = FetchType.EAGER,cascade = CascadeType.ALL)
public List< OrderTransaction> getOrderTransactions(){
return orderTransactions;
}

如何更改标准码以达到与新的设置?

解决方案

这实际上是预期的行为,如果我正确理解您的配置。



您在任何结果中都得到相同的 Order 实例,但是现在您正在使用 OrderTransaction code>,它必须返回相同数量的结果,一个普通的sql连接将返回



所以实际上它应该多次。作者(Gavin King)亲自解释了这一点:此处
它既解释了原因,又解释了如何得到不同的结果。
$ b $ p $ h $也在Hibernate中提到 community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Hibernate_does_not_return_distinct_results_for_a_query_with_outer_join_fetching_enabled_for_a_collection_even_if_I_use_the_distinct_keywordrel =noreferrer> FAQ


对于为集合启用外部联接抓取的查询,Hibernate不会返回不同的结果(即使我使用不同的
关键字)?首先,您需要了解SQL以及SQL中OUTER JOINs如何工作
。如果您不完全理解并理解
SQL中的外连接,请不要继续阅读这个FAQ项目,而是参阅SQL手册或
教程。否则,您将无法理解以下解释
,您将在Hibernate论坛上抱怨此行为。



典型示例可能会返回相同$的重复引用b $ b订单对象:

pre $ 列表结果= session.createCriteria(Order.class)
.setFetchMode(lineItems ,FetchMode.JOIN)
.list();






 < ; class name =Order> 
...
< set name =lineItemsfetch =join>






 列表result = session.createCriteria(Order.class)
.list();
List result = session.createQuery(select o from Order o left join fetch o.lineItems)。list();

所有这些示例都会生成相同的SQL语句:

  SELECT o。*,l。* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID 

想知道为什么有重复吗?查看SQL结果集
Hibernate不会在外部
合并结果的左侧隐藏这些重复项,但会返回驱动表的所有重复项。如果
在数据库中有5个订单,并且每个订单有3个行项目,
,则结果集将为15行。这些查询
的Java结果列表将包含15个元素,所有类型为Order。 Hibernate只会创建5个Order实例
,但是SQL结果集的重复值是
,并保留为这5个实例的重复引用。如果您不懂
这句话,您需要阅读Java和Java堆上的实例与
这样的实例之间的
差异。



(为什么是一个左外连接?如果你有一个没有行
的额外订单,结果集将是16行,NULL填充右边的
side,其中订单项数据用于其他订单,即使没有订单项,您也希望订单
,对不对?如果不是,请在您的HQL中使用内部连接
提取)。


默认情况下,Hibernate不会过滤掉这些重复的引用。
有些人(不是你)实际上需要这个。如何过滤掉它们?



像这样:

  Collection result = new LinkedHashSet(session.create *(...)。list()); 



I have an Order class that has a list of OrderTransactions and I mapped it with a one-to-many Hibernate mapping like so:

@OneToMany(targetEntity = OrderTransaction.class, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
    return orderTransactions;
}

These Orders also have a field orderStatus, which is used for filtering with the following Criteria:

public List<Order> getOrderForProduct(OrderFilter orderFilter) {
    Criteria criteria = getHibernateSession()
            .createCriteria(Order.class)
            .add(Restrictions.in("orderStatus", orderFilter.getStatusesToShow()));
    return criteria.list();
}

This works and the result is as expected.

Now here is my question: Why, when I set the fetch type explicitly to EAGER, do the Orders appear multiple times in the resulting list?

@OneToMany(targetEntity = OrderTransaction.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
    return orderTransactions;
}

How would I have to change my Criteria code to reach the same result with the new setting?

解决方案

This is actually the expected behaviour if I understood your configuration correctly.

You get the same Order instance in any of the results, but since now you are doing a join with the OrderTransaction, it has to return the same amount of results a regular sql join will return

So actually it should apear multiple times. this is explained very well by the author (Gavin King) himself here: It both explains why, and how to still get distinct results


Also mentioned in the Hibernate FAQ :

Hibernate does not return distinct results for a query with outer join fetching enabled for a collection (even if I use the distinct keyword)? First, you need to understand SQL and how OUTER JOINs work in SQL. If you do not fully understand and comprehend outer joins in SQL, do not continue reading this FAQ item but consult a SQL manual or tutorial. Otherwise you will not understand the following explanation and you will complain about this behavior on the Hibernate forum.

Typical examples that might return duplicate references of the same Order object:

List result = session.createCriteria(Order.class)
                    .setFetchMode("lineItems", FetchMode.JOIN)
                    .list();


<class name="Order">
    ...
    <set name="lineItems" fetch="join">


List result = session.createCriteria(Order.class)
                       .list();
List result = session.createQuery("select o from Order o left join fetch o.lineItems").list();

All of these examples produce the same SQL statement:

SELECT o.*, l.* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID

Want to know why the duplicates are there? Look at the SQL resultset, Hibernate does not hide these duplicates on the left side of the outer joined result but returns all the duplicates of the driving table. If you have 5 orders in the database, and each order has 3 line items, the resultset will be 15 rows. The Java result list of these queries will have 15 elements, all of type Order. Only 5 Order instances will be created by Hibernate, but duplicates of the SQL resultset are preserved as duplicate references to these 5 instances. If you do not understand this last sentence, you need to read up on Java and the difference between an instance on the Java heap and a reference to such an instance.

(Why a left outer join? If you'd have an additional order with no line items, the result set would be 16 rows with NULL filling up the right side, where the line item data is for other order. You want orders even if they don't have line items, right? If not, use an inner join fetch in your HQL).

Hibernate does not filter out these duplicate references by default. Some people (not you) actually want this. How can you filter them out?

Like this:

Collection result = new LinkedHashSet( session.create*(...).list() );

这篇关于Hibernate Criteria使用FetchType.EAGER多次返回子项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆