提取联接导致N + 1个查询或引发org.hibernate.QueryException

时间:2019-07-11 14:10:34

标签: java hibernate querydsl

我试图用一个查询对象及其关联的查询列表来获取数据,不幸的是,要么我向数据库提出了N + 1个请求,要么被命中“ org.hibernate.QueryException异常:查询指定的联接获取,但是所有者选择列表中不存在所提取关联的“”。

请让我为您讲解案件。

下面是我的数据模型:

@Table(name = "first_table")
public class FirstObject {
    @Id
    @Column(nullable = false, name = "first_id")
    private Long id;

    @Column(nullable = false, name = "first_param")
    private String param1;

    @ManyToOne
    @JoinColumn(nullable = false, name = "second_id")
    private SecondObject second;

    ...other columns...
}

@Table(name = "second_table")
public class SecondObject {
    @Id
    @Column(nullable = false, name = "second_id")
    private Long id;

    @Column(nullable = false, name = "second_param")
    private Long param2;

    @ManyToOne
    @JoinColumn(nullable = false, name = "third_id")
    private ThirdObject third;

    ...other columns...
}

@Table(name = "third_table")
public class ThirdObject {
    @Id
    @Column(nullable = false, name = "third_id")
    private Long id;

    ...other columns...
}

这对数据库关系是正确的,也正是我在FE上的要求。 我要实现的全部目的是通过一个查询获取所有关联,并提供2个条件:

ConditionBuilder condition = new ConditionBuilder()
            .and(FirstObject.second.param2.eq(some_number))
            .and(FirstObject.param1.eq(some_string));

    return from(FirstObject)
            .join(FirstObject.second).fetchJoin()
            .join(FirstObject.second.third).fetchJoin()
            .where(condition.generate())
            .fetch();

不幸的是,此代码引发异常:

  

org.hibernate.QueryException:查询指定联接获取,但是   获取的关联的所有者不在选择列表中

我可以使它工作,但是可以进行N + 1个查询,但是只有在开发阶段才可以接受,因为这会导致性能问题。

...
.join(FirstObject.second).fetchJoin()
.join(FirstObject.second.third)
...

与此处相同:

...
.join(FirstObject.second)
.join(FirstObject.second.third)
...

我要弄清楚的是如何使休眠状态创建一个像这样的简单查询:

select
    *
from
    first_table table1 
inner join
    second_table table2 
        on table1.second_id=table2.second_id 
inner join
    third_table table3 
        on table2.third_id=table3.third_id 
where
    table1.first_param="some_string"
    table2.second_param=some_number

非常感谢所有帮助,我已经为此奋斗了一段时间,而且确实依靠社区。非常感谢。

1 个答案:

答案 0 :(得分:0)

您应该在实体关系的两侧进行映射:

例如,在FirstObject中,您有以下内容:

@ManyToOne
@JoinColumn(nullable = false, name = "second_id")
private SecondObject second;

因此,在SecondObject中,您应该具有以下条件:

@OneToMany(mappedBy = "second") // this is the name of the field in the class that defines the join relationship
Collection<FirstObject> firstObjects;

ThirdObject中,您应该具有以下内容:

@OneToMany(mappedBy = "third") // this is the name of the field in the class that defines the join relationship
Collection<SecondObject> secondObjects;