小编典典
如果我正确理解你的配置,这实际上是预期的行为。
你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();
...
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() );
2020-03-09