使用内部连接的 Hibernate 单向@OneToOne

Hibernate unidirectional @OneToOne using inner join

我正在使用:

我正在尝试定义 2 类、FirstSecond,以便存在从 First 到 [=14 的一对一映射=].由于我正在尝试通过 Spring Data Rest 托管查询,这会将数据转换为 JSON,我认为进行 EAGER 提取最有意义。

所以,我有以下内容:

@Entity
public class First {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "FIRST_ID")
    private long id;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "SECOND_ID")
    private Second second;

    // more/getters/settings
}

@Entity
public class Second {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "SECOND_ID")
    private long id;

    // more/getters/settings
}

当我搜索 First 类型的数据时,我得到 First 类型的 SELECT 查询,然后每个 Second 的单独 SELECT 查询] 其中 SECOND_ID 与 First.

中引用的外键匹配

对这些数据进行 INNER JOIN 以在单个查询中执行所有操作最有意义。如:

SELECT * FROM FIRST
INNER JOIN SECOND ON FIRST.SECOND_ID

我可以 运行 直接在数据库上查询并得到一个 table 加入两个 tables。

如何让 JPA/Hibernate 执行此操作?这似乎是一个常见的操作,我觉得我遗漏了一些明显的东西。

编辑:请注意,我正在通过 Spring Data Rest 自动生成的 REST 端点使用 运行ning 查询。我已经定义了一个 Spring 数据存储库:

@RepositoryRestResource(path = "first")
public interface FirstRepository extends CrudRepository<First, Long> {
}

然后,通过访问 http://host/first,我导致 Spring 到 运行 一个 findAll 操作,该操作有效,但再次触发大量 SELECT 查询.

首先,只有在使用 EntityManager#find().

加载实体时,才会考虑关联的提取提示

如果您要获取一个单独的第一个实例 (http://host/first/1),您应该会看到正在检索的实例及其在使用 LEFT OUTER JOIN 的 1 个查询中的关联(将关系标记为可选 = false)将导致INNER JOIN) 作为 Spring 数据将委托给 EntityManager#find() 方法。

Spring Data 提供了一种方便的 findAll() 方法,当您选择获取所有实例时,它会简单地生成一个查询 "Select f from First f",并在您点击 http://host/first 时调用。所以这显然不会执行 JOIN FETCH。

如果您要创建查询:

@Query("select f from First f join fetch f.second")
public List<First> findAllEager();

并点击 http://host/first/search/findAllEager 然后这应该将所有内容加载到一个 select.

因为这显然不是很方便,您实际上可以重新定义存储库界面中的 findAll() 方法,如下所示:

@Query("select f from First f join fetch f.second")
public Iterable<First> findAll();

附加信息:当使用 EntityManager#find() 加载实体时,@OneToOne 关联在 Hibernate 中总是急切的,除非标记为非可选和惰性。

试试这个变体:

@RepositoryRestResource(path = "first")
public interface FirstRepository extends CrudRepository<First, Long> {

    @Override
    @EntityGraph(attributePaths = {"second"})
    Iterable<First> findAll();
}