我有一个包含OrderTransactions
列表的Order
类,并将其映射为一个一对多的Hibernate映射,如下所示:
@OneToMany(targetEntity = OrderTransaction.class, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
return orderTransactions;
}
这些Order
还有一个字段orderStatus
,用于根据以下条件进行筛选:
public List<Order> getOrderForProduct(OrderFilter orderFilter) {
Criteria criteria = getHibernateSession()
.createCriteria(Order.class)
.add(Restrictions.in("orderStatus", orderFilter.getStatusesToShow()));
return criteria.list();
}
这是可行的,结果和预期的一样。
下面是我的问题:为什么当我显式地将fetch类型设置为EAGER
时,Order
会在结果列表中多次出现?
@OneToMany(targetEntity = OrderTransaction.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
return orderTransactions;
}
我必须如何更改我的标准代码才能达到与新设置相同的结果?
发布于 2010-01-03 23:15:55
如果我正确理解了您的配置,这实际上是预期的行为。
在任何结果中都会得到相同的Order
实例,但是由于现在您正在使用OrderTransaction
进行连接,因此它必须返回与常规sql连接相同数量的结果
所以实际上它应该出现多次。作者(Gavin King)本人here很好地解释了这一点:它既解释了原因,也解释了如何仍然获得明显的结果
在Hibernate FAQ中也提到:
对于为集合启用了外部连接获取的查询,
Hibernate不会返回distinct结果(即使我使用了distinct关键字)?首先,您需要了解SQL以及外连接在SQL中是如何工作的。如果您不能完全理解和理解SQL中的外部连接,请不要继续阅读本常见问题解答,而应参考SQL手册或教程。否则,您将无法理解下面的解释,并且您将在Hibernate论坛上抱怨此行为。
可能返回相同Order对象的重复引用的典型示例:
List result = session.createCriteria(Order.class) .setFetchMode("lineItems",FetchMode.JOIN) .list();
..。
List 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行,右侧填充为空,其中行项目数据用于其他订单。即使他们没有行项目,你也想要订单,对吧?如果没有,请在HQL中使用内部连接获取)。
默认情况下,Hibernate不会过滤掉这些重复的引用。有些人(而不是你)实际上想要这样。你怎么过滤掉它们呢?
如下所示:
采集结果=新的LinkedHashSet( session.create*(...).list() );
发布于 2010-01-04 18:46:44
除了Eran提到的之外,另一种获得你想要的行为的方法是设置结果转换器:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
发布于 2014-04-07 23:05:36
试一试
@Fetch (FetchMode.SELECT)
例如
@OneToMany(targetEntity = OrderTransaction.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Fetch (FetchMode.SELECT)
public List<OrderTransaction> getOrderTransactions() {
return orderTransactions;
}
https://stackoverflow.com/questions/1995080
复制相似问题