我有一对多关系中的两个类和一个有点奇怪的HQL查询。即使我已经阅读了一些已经发布的问题,对我来说也不清楚。
Class Department{
@OneToMany(fetch=FetchType.EAGER, mappedBy="department")
Set<Employee> employees;
}
Class Employee{
@ManyToOne
@JoinColumn(name="id_department")
Department department;
}
当我使用以下查询时,我得到重复的Department对象:
session.createQuery("select dep from Department as dep left join dep.employees");
因此,我必须使用不同的:
session.createQuery("select distinct dep from Department as dep left join dep.employees");
这是一种预期的行为吗?我认为这与SQL比较是不寻常的。
这个问题在Hibernate FAQ中有详尽的解释:
首先,您需要了解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">
...
</class>
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() );
LinkedHashSet过滤掉重复的引用(它是一个集合),并保留插入顺序(结果中元素的顺序)。那太简单了,因此您可以通过许多不同且更困难的方式来做到这一点:
List result = session.createCriteria(Order.class)
.setFetchMode("lineItems", FetchMode.JOIN)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
<class name="Order">
...
<set name="lineItems" fetch="join">
List result = session.createCriteria(Order.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
List result = session.createQuery("select o from Order o left join fetch o.lineItems")
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) // Yes, really!
.list();
List result = session.createQuery("select distinct o from Order o left join fetch o.lineItems").list();
最后一个很特别。看来您在这里使用SQL
DISTINCT关键字。当然,这不是SQL,这是HQL。在这种情况下,这种区别只是结果转换器的捷径。是的,在其他情况下,HQL变量将直接转换为SQL
DISTINCT。并非在这种情况下:您无法在SQL级别上过滤掉重复项,产品/联接的本质禁止这样做-
您想要重复项或没有获得所需的所有数据。当结果集被编组到对象中时,所有对重复项的过滤都在内存中进行。同样显而易见的是,为什么基于结果集基于行的“限制”操作(例如setFirstResult(5)和setMaxResults(10))无法与这类急切的获取查询一起使用。如果您将结果集限制为一定数量的行,您随机切断数据。有一天,Hibernate可能很聪明,知道如果调用setFirstResult()或setMaxResults(),则不应使用联接,而应使用第二个SQL
SELECT。尝试一下,您的Hibernate版本可能已经足够聪明了。如果不是,则编写两个查询,一个查询用于限制内容,另一个查询用于快速获取。您是否想知道为什么带有Criteria查询的示例没有忽略映射中的fetch
=“ join”设置,但是HQL不在乎?阅读下一个常见问题解答。您是否想知道为什么带有Criteria查询的示例没有忽略映射中的fetch =“
join”设置,但是HQL不在乎?阅读下一个常见问题解答。您是否想知道为什么带有Criteria查询的示例没有忽略映射中的fetch =“
join”设置,但是HQL不在乎?阅读下一个常见问题解答。
问题内容: 我想获取一对一关系的ID,而不加载整个对象。我以为可以使用如下所示的延迟加载来做到这一点: 我希望f.getBar() 不 触发另一个提取。我希望hibernate给我一个代理对象,该代理对象使我可以调用.getId()而不实际获取Bar对象。 我究竟做错了什么? 问题答案: 使用 财产访问策略 代替 采用 现在工作正常! 如果调用 不是标识符getter方法的 任何方法 , 则会初始
问题内容: 我正在使用hibernate4+。 我有两个示例表。 表A 表B 表A(1)-(n)表B关系 我可以不使用连接就在对象B中获取A的ID吗? 像int aid = b.getA()。getId(); // b是B的实例; 尽管在声明类B时可以使用int值而不是A。但是另一个服务层将A与join一起使用。 我可以只获取id(fk)值吗? 请帮忙。 问题答案: 是的,因为代理仍然包含ID。要
问题内容: var arrObj = [{a:1, b:2},{c:3, d:4},{e:5, f:6}]; 如何将其合并为一个obj? 问题答案: 如果您的环境支持,那么您可以像这样简洁地进行操作 ES5解决方案: 您可以使用这样的 此解决方案仅将的所有键及其值收集在中的每个对象中,最终将结果返回给我们。 这张支票 有必要确保我们在结果中不包括所有继承的可枚举属性。
用户表结构:用户 id、名称、用户名、密码、创建时间、更新时间 文章表结构:文章 id、标题、内容、创建时间、更新时间 关系表:文章\用户 id、文章id、用户id处于活动状态、创建时间、更新时间 标签 id、名称、用户id、创建时间、更新时间 透视表项目用户与标记的关系。表:文章\用户\标签 标签号,物品号,用户号 我想连接这些表,以便可以像这样或类似的格式访问 并且应该能够创建/更新smth,
我的问题可能看起来很傻。我是JPA的新手,试图理解它的基本概念。我发现有一种@multi-to-one实体关系可以在那里使用。我的问题是,为什么有人想在拥有“一对多”关系的同时使用它?我的意思是,拥有后一个就足够了解关系并发送查询了,对吗?如果没有,请解释。也许我对这两种关系的看法是完全错误的。请提供一个场景作为示例,以便我更好地理解。谢谢