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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (37)

我有一个Order有一个列表的类,OrderTransactions我用一对多的Hibernate映射映射它,像这样:

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

这些Orders也有一个字段orderStatus,用于按以下标准进行过滤:

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

这工作,结果如预期。

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

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

我将如何更改标准码以达到与新设置相同的结果?

提问于
用户回答回答于

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

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

所以实际上它应该多次出现。作者(Gavin King)自己在这里解释得非常好:这既解释了原因,又解释了如何获得明显的结果

在Hibernate FAQ中也提到:

对于集合启用外部联接抓取的查询,Hibernate不会返回不同的结果(即使我使用distinct关键字)?首先,您需要了解SQL以及OUTER JOIN在SQL中的工作方式。如果您不完全理解并理解SQL中的外连接,请不要继续阅读本FAQ文档,而应参阅SQL手册或教程。否则,你不会理解下面的解释,你会在Hibernate论坛上抱怨这种行为。 典型的例子可能会返回同一Order对象的重复引用: 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(); 所有这些示例都会生成相同的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填充右侧,其中订单项数据用于其他订单。他们没有订单项,对不对?如果没有,请在你的HQL中使用内部联合提取)。 Hibernate在默认情况下不会过滤掉这些重复的引用。有些人(不是你)实际上想要这样。你怎么能过滤掉它们? 这个: Collection result = new LinkedHashSet( session.create*(...).list() );

用户回答回答于

除了Eran提到的内容之外,另一种获得所需行为的方法是设置结果转换器:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

所属标签

可能回答问题的人

  • 最爱开车啦

    8 粉丝503 提问6 回答
  • 优惠活动秘书

    0 粉丝2 提问6 回答
  • 天使的炫翼

    17 粉丝531 提问6 回答
  • Richel

    6 粉丝0 提问5 回答

扫码关注云+社区

领取腾讯云代金券