我有一个Order
类,它有一个OrderTransactions
列表,我用一对多的HibernateMap来Map它,如下所示:
@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;
}
我必须如何更改我的条件代码才能在新设置下达到相同的结果?
8条答案
按热度按时间bq8i3lrv1#
如果我正确理解了您的配置,这实际上是预期的行为。
在任何结果中都会得到相同的
Order
示例,但由于现在要使用OrderTransaction
执行连接,因此它必须返回与常规sql连接相同数量的结果所以实际上它 * 应该 * 出现多次。这是解释得很好的作者(加文金)自己在这里:它既解释了原因,也解释了如何仍然获得不同的结果
在Hibernate [常见问题][2]中也提到:
可能返回同一Order对象的重复引用的典型示例:
所有这些示例都生成相同的SQL语句:
想知道为什么会有重复项吗?看看SQL结果集,Hibernate不会在外连接结果的左侧隐藏这些重复项,而是返回驱动表的所有重复项。如果数据库中有5个订单,每个订单有3个行项目,结果集将是15行。这些查询的Java结果列表将有15个元素。所有的Order类型。Hibernate只会创建5个Order示例,但是SQL结果集的副本会作为对这5个示例的重复引用而保留。如果你不理解最后一句话,你需要阅读Java以及Java堆上的示例和对这样一个示例的引用之间的区别。
(Why左外连接?如果您有一个没有行项目的附加订单,结果集将是16行,右侧填充NULL,行项目数据用于其他订单。即使订单没有行项目,您也需要订单,对吗?如果没有,请在HQL中使用内连接提取)。
Hibernate默认情况下不会过滤掉这些重复引用,有些人(不是你)实际上想要这个,你怎么能过滤掉它们呢?
就像这样:
ix0qys7i2#
除了Eran提到的方法之外,另一种获得所需行为的方法是设置结果转换器:
4dbbbstv3#
尝试
例如
}
tct7dpnv4#
不要使用List和ArrayList,而要使用Set和HashSet。
y3bcpkx15#
使用Java 8和Streams,我在我的实用方法中添加了以下返回语句:
流删除重复的速度非常快。我在我的Entity类中使用注解,如下所示:
我想在我的应用程序中,如果我需要数据库中的数据,最好在方法中使用会话。当我完成时,关闭会话。当然,设置我的实体类使用最简单的获取类型。我去重构。
lrl1mhuk6#
我在获取2个关联集合时遇到了同样的问题:用户有2个角色(设置)和2份膳食(列表),膳食重复。
DISTINCT没有帮助(DATA-JPA查询):
最后我找到了两个解决办法:
1.将列表更改为LinkedHashSet
1.使用仅具有字段"meal"和类型LOAD的EntityGraph,这将加载声明的角色(EAGER和BatchSize = 200以防止N +1问题):
最终溶液:
更新:对于Spring Boot 3.0(JPA 3.1),它仅适用于
EntityGraphType.FETCH
:fcy6dtqo7#
而不是使用黑客像:
Set
而不是List
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
不修改SQL查询,我们可以使用(引用JPA规范)
这修改了所得到的SQL查询,因此在其中具有
DISTINCT
。c0vxltue8#
这听起来不是一个很好的行为,应用外部连接并带来重复的结果。唯一的解决方案是使用流过滤我们的结果。感谢java8提供了更简单的过滤方法。