我有一个Order包含列表的类,并使用OrderTransactions一对多的Hibernate映射将其映射,如下所示:
Order
OrderTransactions
@OneToMany(targetEntity = OrderTransaction.class, cascade = CascadeType.ALL) public List<OrderTransaction> getOrderTransactions() { return orderTransactions; }
这些Order还具有一个field orderStatus,用于根据以下条件进行过滤:
orderStatus
public List<Order> getOrderForProduct(OrderFilter orderFilter) { Criteria criteria = getHibernateSession() .createCriteria(Order.class) .add(Restrictions.in("orderStatus", orderFilter.getStatusesToShow())); return criteria.list(); }
这可以正常工作,并且结果符合预期。
现在 是我的问题 :为什么当我将fetch类型显式设置为时EAGER,Orders在结果列表中出现多次?
EAGER
@OneToMany(targetEntity = OrderTransaction.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL) public List<OrderTransaction> getOrderTransactions() { return orderTransactions; }
我如何更改我的Criteria代码才能在新设置下达到相同的结果?
如果我正确理解您的配置,这实际上是预期的行为。
您Order在任何结果中都得到相同的实例,但是由于您现在正在使用进行联接OrderTransaction,因此它必须返回与常规sql联接将返回的结果相同的结果量
OrderTransaction
所以实际上它 应该 出现多次。这是由作者(是GavinKing)自己解释得非常好这里:它既解释了为什么,以及如何仍然得到不同的结果
在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语句:
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 > > > 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.
(为什么要使用左外部联接?如果您有其他没有订单项的订单,那么结果集将是16行,右侧填充NULL,而订单项数据用于其他订单。即使您想要订单,即使他们没有订单项,对吗?如果没有,请在您的HQL中使用内部联接提取)。 默认情况下,Hibernate不会过滤掉这些重复的引用。有些人(不是您)实际上想要这个。如何过滤掉它们? 像这样: Collection result = new LinkedHashSet( session.create*(...).list() );
(为什么要使用左外部联接?如果您有其他没有订单项的订单,那么结果集将是16行,右侧填充NULL,而订单项数据用于其他订单。即使您想要订单,即使他们没有订单项,对吗?如果没有,请在您的HQL中使用内部联接提取)。
默认情况下,Hibernate不会过滤掉这些重复的引用。有些人(不是您)实际上想要这个。如何过滤掉它们?
像这样:
Collection result = new LinkedHashSet( session.create*(...).list() );