Java 一对多关系获取重复对象而不使用;独特的;。为什么?

Java 一对多关系获取重复对象而不使用;独特的;。为什么?,java,hibernate,hql,distinct,one-to-many,Java,Hibernate,Hql,Distinct,One To Many,我有两个一对多关系类和一个有点奇怪的HQL查询。即使我读过一些已经贴出的问题,我也不清楚 Class Department{ @OneToMany(fetch=FetchType.EAGER, mappedBy="department") Set<Employee> employees; } Class Employee{ @ManyToOne @JoinColumn(name="id_department") Department department

我有两个一对多关系类和一个有点奇怪的HQL查询。即使我读过一些已经贴出的问题,我也不清楚

Class Department{
   @OneToMany(fetch=FetchType.EAGER, mappedBy="department")
   Set<Employee> employees;
}
Class Employee{
   @ManyToOne
   @JoinColumn(name="id_department")
   Department department;
}
班级部门{
@OneToMany(fetch=FetchType.EAGER,mappedBy=“department”)
设置员工;
}
班级员工{
@许多酮
@JoinColumn(name=“id\u部门”)
部门,;
}
使用以下查询时,我会得到重复的部门对象:

session.createQuery(“选择dep from Department作为dep left join dep.employees”)

因此,我必须使用不同的:

session.createQuery(“从部门中选择不同的dep作为dep left join dep.employees”)


这种行为是预期的吗?我认为这是不寻常的,因为它与SQL相比。

< P>这个问题被彻底解释为:

首先,您需要了解SQL以及外部联接在SQL中的工作方式。如果 您不完全理解和理解SQL中的外部联接,不是吗 继续阅读此FAQ项目,但请参阅SQL手册或教程。 否则,您将无法理解以下解释,并且 将在Hibernate论坛上抱怨这种行为。典型的 可能返回相同顺序的重复引用的示例 对象:

所有这些示例都生成相同的SQL语句:

想知道为什么会有复制品吗?看看SQL 结果集,Hibernate不会在左侧隐藏这些重复项 但返回外部联接结果的所有副本 驾驶台。如果数据库中有5个订单,每个订单 有3行项目,结果集将为15行。Java结果列表 这些查询中有15个元素,都是Order类型。只有5个 订单实例将由Hibernate创建,但 SQL resultset被保留为对这些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(标准.DISTINCT\u ROOT\u实体)
.list();
...  
列表结果=session.createCriteria(Order.class)
.setResultTransformer(标准.DISTINCT\u ROOT\u实体)
.list();
列表结果=session.createQuery(“从订单中选择o左连接提取o.lineItems”)
.setResultTransformer(Criteria.DISTINCT\u ROOT\u ENTITY)//是的,真的!
.list();
List result=session.createQuery(“从顺序o中选择不同的o左连接提取o.lineItems”).List();
最后一个是特别的。看起来您正在使用SQL 这里有不同的关键字。当然,这不是SQL,这是HQL。这 在本例中,distinct只是结果转换器的快捷方式。 是的,在其他情况下,HQL distinct将直接转换为SQL 不同的在这种情况下不是这样的:您不能同时筛选出重复项 SQL级别,产品/连接的本质禁止这样做-您想要的 重复项,否则您无法获得所需的所有数据。所有这些 当resultset为 编组为对象。也应该很清楚为什么结果集 基于行的“限制”操作,例如setFirstResult(5)和 setMaxResults(10)不适用于此类急切获取查询。 如果将结果集限制为一定数量的行,则会切断 随机数据。有一天Hibernate可能会聪明到知道如果 调用setFirstResult()或setMaxResults(),则不应使用联接, 但是第二个SQL选择。试试看,你的Hibernate版本可能会 已经足够聪明了。如果不是,写两个查询,一个用于限制 东西,另一个是急切的抓取。你想知道为什么会这样吗 带有条件查询的示例没有忽略fetch=“join” 在映射中设置,但HQL不在乎?阅读下一个常见问题


使用结果转换器
标准。不同的\u根\u实体

List result = session.createQuery("hql query")  
                        .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)  
                        .list();

我从弗拉德·米哈尔恰先生那里学到了一个很好的建议。有关更多提示:


为什么要让
左加入
,只是简单的
部门
,而且你的获取类型也很急切。sql输出是什么?实际上,查询有一个where子句,我需要为每个员工设置一个条件,在这种情况下,来自部门的
对我没有帮助<代码>选择Department中的dep作为dep left加入dep.employees emp,其中emp.enddate>current_date()
我在这方面遇到性能问题。我在想,Hibernate可能正在尝试为每个重复项创建Java对象,然后执行一个不同的操作?因此,基本上做大量不必要的对象创建会导致速度减慢,是这样吗?有没有更有效的解决方案?
SELECT o.*, l.* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID   
Collection result = new LinkedHashSet( session.create*(...).list() );  
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();       
List result = session.createQuery("hql query")  
                        .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)  
                        .list();
    list = session.createQuery("SELECT DISTINCT c FROM Supplier c "
            +"LEFT JOIN FETCH c.salesList WHERE c.name LIKE :p1"
            , Supplier.class)
            .setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
            .setParameter("p1", name + "%")
            .list();