Hibernate Criteria使用FetchType.EAGER多次返回子项

Hibernate Criteria使用FetchType.EAGER多次返回子项

我有一个Order包含列表的类,OrderTransactions我用一对多的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类型时EAGEROrders会在结果列表中多次出现?

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

如何更改我的条件代码以使用新设置达到相同的结果?


四季花海
浏览 637回答 3
3回答

临摹微笑

如果我正确理解您的配置,这实际上是预期的行为。你Order在任何结果中得到相同的实例,但是从现在你开始与OrderTransaction它连接,它必须返回相同数量的结果,常规的sql join将返回实际上它应该多次出现。作者(Gavin King)自己在这里解释了这一点:它既解释了原因,又解释了如何获得截然不同的结果在Hibernate&nbsp;FAQ中也提到过:对于集合启用了外连接提取的查询,Hibernate不会返回不同的结果(即使我使用distinct关键字)?首先,您需要了解SQL以及OUTER JOIN在SQL中的工作方式。如果您不完全理解和理解SQL中的外连接,请不要继续阅读此FAQ项,而是查阅SQL手册或教程。否则你将无法理解以下解释,你会在Hibernate论坛上抱怨这种行为。可能返回同一Order对象的重复引用的典型示例:List&nbsp;result&nbsp;=&nbsp;session.createCriteria(Order.class) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.setFetchMode("lineItems",&nbsp;FetchMode.JOIN) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.list();<class&nbsp;name="Order"> &nbsp;&nbsp;&nbsp;&nbsp;... &nbsp;&nbsp;&nbsp;&nbsp;<set&nbsp;name="lineItems"&nbsp;fetch="join">List&nbsp;result&nbsp;=&nbsp;session.createCriteria(Order.class) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.list();List&nbsp;result&nbsp;=&nbsp;session.createQuery("select&nbsp;o&nbsp;from&nbsp;Order&nbsp;o&nbsp;left&nbsp;join&nbsp;fetch&nbsp;o.lineItems").list();所有这些示例都生成相同的SQL语句:SELECT&nbsp;o.*,&nbsp;l.*&nbsp;from&nbsp;ORDER&nbsp;o&nbsp;LEFT&nbsp;OUTER&nbsp;JOIN&nbsp;LINE_ITEMS&nbsp;l&nbsp;ON&nbsp;o.ID&nbsp;=&nbsp;l.ORDER_ID想知道重复的原因在哪里?查看SQL结果集,Hibernate不会在外部联接结果的左侧隐藏这些重复项,但会返回驱动表的所有重复项。如果数据库中有5个订单,并且每个订单有3个订单项,则结果集将为15行。这些查询的Java结果列表将包含15个元素,所有元素都是Order。Hibernate只会创建5个Order实例,但SQL结果集的重复项将保留为对这5个实例的重复引用。如果您不理解最后一句,您需要阅读Java以及Java堆上的实例与对此类实例的引用之间的区别。(为什么左外连接?如果你有一个没有行项目的附加订单,结果集将是16行,其中NULL填充右侧,其中行项目数据用于其他顺序。即使是它们没有行项目,对吧?如果没有,请在HQL中使用内部联接提取)。默认情况下,Hibernate不会过滤掉这些重复的引用。有些人(不是你)真的想要这个。你怎么能过滤掉它们?像这样:Collection&nbsp;result&nbsp;=&nbsp;new&nbsp;LinkedHashSet(&nbsp;session.create*(...).list()&nbsp;);

慕标琳琳

除了Eran所提到的,另一种获得所需行为的方法是设置结果转换器:criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java