java - QueryDSL @OneToOne Join-FetchMode 与 Hibernate

标签 java hibernate querydsl

假设我们有一个简单的实体“Customer”,它与实体“Address”具有一对一的关系。外键在地址端。

@Entity
public class Customer extends EntityBase {
    @Column(name = "name", nullable = true)
    private String name;

    @OneToOne(mappedBy = "customer")
    private Address address;

    // getter, setter, ...
}

@Entity
public class Address extends EntityBase {
    @OneToOne(optional = false)
    private Customer customer;

    @Column(nullable = true)
    private String street;
    @Column(nullable = true)
    private String zip;
    @Column(nullable = true)
    private String city;

    // getter, setter, ...
}

如果您现在使用 Hibernate 加载所有 Customer 实体并将生成的查询打印到控制台,您可以看到 Hibernate 在内部仅触发一个查询。

session.createCriteria(Customer.class).list();

Hibernate 做什么:

select
    this_.id as id1_1_1_,
    this_.name as name2_1_1_,
    address2_.id as id1_0_0_,
    address2_.city as city2_0_0_,
    address2_.customer_id as customer5_0_0_,
    address2_.street as street3_0_0_,
    address2_.zip as zip4_0_0_ 
from
    Customer this_ 
left outer join
    Address address2_ 
        on this_.id=address2_.customer_id

如果您使用 QueryDSL 加载 Customer 实体,它将运行一次计数查询(符合预期且正常),一次针对 Customer 实体的选择查询以及一次针对结果集中每个客户的查询。这意味着,如果我想加载 1000 个客户,它将运行 1002 个 SQL 查询。这会产生大量网络流量并降低应用程序的速度。

new HibernateQuery<Customer>(session).from(QCustomer.customer).fetchResults();

带 QueryDSL 的 Hibernate 做什么:

select
    count(customer0_.id) as col_0_0_
from
    Customer customer0_

select
    customer0_.id as id1_1_,
    customer0_.name as name2_1_
from
    Customer customer0_

select
    address0_.id as id1_0_1_,
    address0_.city as city2_0_1_,
    address0_.customer_id as customer5_0_1_,
    address0_.street as street3_0_1_,
    address0_.zip as zip4_0_1_,
    customer1_.id as id1_1_0_,
    customer1_.name as name2_1_0_
from
    Address address0_
inner join
    Customer customer1_
        on address0_.customer_id=customer1_.id
where
    address0_.customer_id=?

问题:
是否可以为 QueryDSL 查询设置类似全局 FetchMode 的东西。在 Hibernate 中,您可以使用 @Fetch(FetchMode.JOIN) 指定它,但不幸的是,它会被 QueryDSL 忽略。

所以我的目标是使用 QueryDSL 加载 1000 个客户并且只运行 2 个查询(计数 + 选择)。

我已经知道有一种方法可以指定这样的内容:

new HibernateQuery<Customer>(session)
    .from(QCustomer.customer)
    .leftJoin(QCustomer.customer.address).fetchJoin()
    .fetchResults();

但这很容易出错,因为您必须在每个查询中指定它,而且我不想自己声明每个连接。 QueryDSL 在使用谓词时已经自动完成了:

new HibernateQuery<Customer>(session)
    .from(QCustomer.customer)
    .where(QCustomer.customer.address.street.in("Musterstraße 12"))
    .fetchResults();

所以我想使用上面的表达式加载我的客户,但我不想向我的数据库发出数千个请求,我也不想自己声明每个连接。这可能吗?

我在这里推送了一个示例项目:https://github.com/MatWein/testproject

最佳答案

曾经遇到过同样的问题。但我正在使用 Hibernate JPA 标准查询。 如果您想在一个查询中获得结果,那么一种方法是使用

@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name = "address_id", insertable = false, updatable = false, referencedColumnName = "id")
private Address address;

或者我有一个标准查询的解决方案。可能会帮助您将其转换为 DSL。

创建 Customer 类的根。

Root<Customer> root = . . .
Join<Customer, Address> join = (Join<Customer, Address>)root.fetch(Customer_.address);

引用我的Question

关于java - QueryDSL @OneToOne Join-FetchMode 与 Hibernate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54153223/

相关文章:

postgresql - 来自 Postgres 的 QueryDSL 和 SQL 函数

python - elasticsearch python 查询 - 按字段分组然后计数

java - 将文件从 HDFS 复制到本地计算机

java - JButton 被工具提示文本渲染为不可点击

hibernate - 使用LazyList时,Grails一对多关系无法创建回到父级的链接

java - Hibernate NOT IN 子查询

java - Spring Boot Querydsl : Sorting - sometimes not working for specifc enitity attribute

java - LOGGER.error(exception.getMessage()) 和 LOGGER.error(exception.getMessage(), exception) 有什么区别

java - 检查 do while 循环

hibernate - hibernate 列表与4个表不同