【问题标题】:JOIN FETCH in spring-data-jpa does not fetch lazy associationsspring-data-jpa 中的 JOIN FETCH 不获取惰性关联
【发布时间】:2019-10-01 17:17:00
【问题描述】:

我在获取 spring-data-jpa 中的惰性 @ManyToMany 关联时遇到问题。 我有一个电影列表,它与使这部电影成为最爱的用户和类型列表相关:

@Entity
@Table("movie")
public class Movie {
...

  @ManyToMany(fetch = FetchType.EAGER)
  @JoinTable(...)
  private List<Genre> genres;

  @ManyToMany
  @JoinTable(name = "users_movies",
            joinColumns = @JoinColumn(name = "movie_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
  private List<User> users = new ArrayList<>;
}

流派还与将该流派标记为收藏的用户相关联:

@Entity
@Table("genre")
public class Genre {
....
  @ManyToMany
  @JoinTable(name = "users_genres",
            joinColumns = @JoinColumn(name = "genre_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
  private List<User> users;
}

我有一个包含以下方法/查询的存储库,它必须按最喜欢的流派返回所有电影并加载电影的用户,以便我可以显示用户是否将电影标记为收藏:

@Query(value = "SELECT movie FROM Movie movie " +
               "JOIN movie.genres genre JOIN genre.users grenreUser " +
               "LEFT JOIN FETCH movie.users " +
               "WHERE grenreUser.id = :userId",
      countQuery = "SELECT COUNT(movie) FROM Movie movie " +
                   "JOIN movie.genres genre JOIN genre.users grenreUser " +
                   "LEFT JOIN movie.users " +
                   "WHERE grenreUser.id = :userId")
Page<Movie> getAllMoviesByFavoriteGenres(@Param("userId") String userId, Pageable);

但是这里我遇到了一个问题,movie.getUsers() 在执行这个查询后是空的。

found 认为使用@EntityGraph 会有所帮助,但它没有movie.getUsers() 关联仍然是空的。

为了测试,我也尝试将此关联设为FetchType.EAGER,但它仍然是空的。

我没有想法,所以我将不胜感激。

更新: 数据库中不存在用户可能不是问题,因为我有另一个查询,该查询仅提取用户在收藏夹用户类型中标记为收藏夹的电影。因此,如果用户不存在于 DB 中,则查询将返回空结果,但我确实得到了结果,尽管 movie.getUsers() 为空。这是方法/查询:

@Query(value = "SELECT movie FROM Movie movie " +
                   "JOIN movie.genres genre " +
                   "JOIN FETCH movie.users user " +
                   "WHERE user.id = :userId AND :userId MEMBER OF genre.users",
          countQuery = "*same but with count*")
Page<Movie> getAllFavoriteMoviesByFavoriteGenres(@Param("userId") String userId, Pageable);

【问题讨论】:

  • 您确定应该是 Movie.users 吗?在示例中,Movie 是一个类,并且有一个用户(不是用户)非静态列表成员。
  • @LajosArpad 这是一个错字,否则我会得到休眠异常
  • 好的,我明白了,但即使在编辑之后,您仍然拥有 Movie.users。您是否有一个称为 users 的静态成员,或者您的意思是实例级用户,例如 m.users,其中 m 是 Movie 的实例?
  • @LajosArpad 很抱歉造成混淆,我指的是 Movie 类的非静态成员。也会编辑它
  • 谢谢。如果您直接使用正在测试的 userId 值运行查询,您会获得用户的值吗?

标签: java hibernate jpa spring-data-jpa spring-data


【解决方案1】:

是的,单向映射应该可以工作。我对您正在做的基本示例没有任何问题。这应该是一个很好的起点,可以帮助您弄清楚差异是什么。我注意到我没有在countQuery 中加入movie.users

@Entity
public class Movie {
    @Id @GeneratedValue private Long id;
    @ManyToMany
    private Set<Genre> genres;
    @ManyToMany
    private Set<User> users;

@Entity
public class Genre {
    @Id @GeneratedValue private Long id;        
    @ManyToMany
    private Set<User> users;

@Entity
public class User {
    @Id @GeneratedValue private Long id;

还有存储库:

public interface MovieRepository extends JpaRepository<Movie, Long> {
    @Query(value = "SELECT movie FROM Movie movie " +
            "JOIN movie.genres genres JOIN genres.users users LEFT JOIN FETCH movie.users " +
            "WHERE users.id = :userId", 
    countQuery = "SELECT COUNT(movie) FROM Movie movie " +
            "JOIN movie.genres genres JOIN genres.users users " +
            "WHERE users.id = :userId")
    Page<Movie> getAllMoviesByFavoriteGenres(@Param("userId") Long userId, Pageable page);

并使用它:

@Override
public void run(String... args) throws Exception {
    create();
    System.out.println("something");
    Page<Movie> movies = movieRepo.getAllMoviesByFavoriteGenres(1L, PageRequest.of(0, 10));
    movies.forEach(System.out::println);
}

private void create() {
    User u1 = new User();
    userRepo.save(u1);

    Set<User> users = Collections.singleton(u1);

    Genre g1 = new Genre();
    g1.setUsers(users);
    genreRepo.save(g1);

    Set<Genre> genres = Collections.singleton(g1);

    Movie m1 = new Movie();
    m1.setGenres(genres);
    m1.setUsers(users);
    movieRepo.save(m1);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-21
    • 2021-12-19
    • 1970-01-01
    • 2013-02-03
    • 2017-01-18
    • 1970-01-01
    • 2022-11-12
    • 2016-02-08
    相关资源
    最近更新 更多