使用内部连接的 Hibernate 单向@OneToOne
Hibernate unidirectional @OneToOne using inner join
我正在使用:
- Spring 开机
- Spring 数据 JPA
- Spring数据休息
- 休眠
- 嵌入式 H2 数据库
我正在尝试定义 2 类、First
和 Second
,以便存在从 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();
}
我正在使用:
- Spring 开机
- Spring 数据 JPA
- Spring数据休息
- 休眠
- 嵌入式 H2 数据库
我正在尝试定义 2 类、First
和 Second
,以便存在从 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();
}