【发布时间】:2019-03-02 08:11:36
【问题描述】:
我有以下实体,每个实体都有一个 CrudRepository:
@Entity
class Movie {
@Id Long id;
@Column String name;
@ManyToOne Person director;
}
@Entity
class Person {
@Id Long id;
@Column String name;
}
我的控制器如下所示:
@RestController
@RequestMapping("/movies")
class MovieController {
private MovieRepository movies = ...;
private PersonRepository people = ...;
@PostMapping
public Movie create(@RequestBody MovieRequest request) {
// Get the director
Person director = people.findById(request.directorId);
// Create the new movie
Movie movie = new Movie();
movie.name = request.name;
movie.director = director;
// Save the new movie
return movies.save(movie);
}
}
class MovieRequest {
String name;
Long directorId
}
如您所见,create 方法首先通过其 id 加载导演,然后创建新电影并最终保存它。这会导致两次访问数据库:第一次检索导演,第二次保存电影。
在这种情况下,这不是一个大问题,但可能存在具有大量关系的实体,这意味着可能会执行大量查询来实现单个插入。
问题:我想将新电影保存在单个数据库操作中。有没有办法避免最初的人员查询?有没有更好的方法来处理这种情况?
【问题讨论】:
-
你熟悉 findById 和 getOne 的区别吗?由于您只需要对导演的引用而不是整个对象,请看一下这个问题stackoverflow.com/q/5482141/7634201
-
感谢@C.Weber,这几乎就是我想要的。正如您提到的
getOne方法在这种情况下比findById更好,因为它获取引用而不是整个实体,但它仍然会去数据库检查 id 是否存在,如果不存在则抛出EntityNotFoundException不。我真的很想把它作为一个单一的数据库操作来做,这看起来可能吗? -
您正在使用 Hibernate 作为 JPA 提供程序?只要您不访问标识符以外的任何属性,AFAIK Hibernate 就不会初始化代理。可以通过以下设置 hibernate.jpa.compliance.proxy 更改此行为(默认应为 false)。如果设置为 true,它还将在访问标识符时初始化代理。有关更多信息,请参阅Hib User Guide。我的猜测是你正在访问代理,标志设置为 true 或者我的信息是旧的 :)
-
@ESala MOVIE 表中有哪些列??
-
@C.Weber 是的,我正在使用 Hibernate 但不是直接使用,我在顶部使用 spring-data-jpa。我刚刚使用
PersonRepository扩展JpaRepository并调用getOne(id)对其进行了测试,但它仍然获取实体。这是记录的查询:select person0_.id as id1_1_0_, person0_.name as name2_1_0_ from person person0_ where person0_.id=?。
标签: java spring spring-mvc spring-data-jpa spring-data