Spring Data JPA - 多对多查询

3
我有两个实体:Person 和 Movie。
@Entity
public class Person {
..some fields

@ManyToMany(fetch = FetchType.LAZY, mappedBy = "actors")
@OrderBy("id")
private Set<Movie> moviesActor = new TreeSet<>();

}

@Entity
public class Movie {
..fields
@JoinTable(name = "actor_movie",
            joinColumns = { @JoinColumn(name = "movie_id") },
            inverseJoinColumns = { @JoinColumn(name = "actor_id") })
    private Set<Person> actors = new TreeSet<>();
}

由于存在多对多的关系,所以需要创建一个新表actor_movie来维护它。那么如何获取每个拥有电影的人呢?我想要的是获取actor_movie表中存在的每个人。我尝试使用Spring data jpa,但无法找到正确的查询语句。

4个回答

2

实体关系的最佳实践:

  1. 始终使用 fetch = FetchType.LAZY
  2. 当您想要获取关系的另一侧时,请使用 JOIN FETCH 查询。
    这也解决了 hibernate 的 LazyInitializationException 问题。
  3. 始终使用 spring.jpa.open-in-view=false

示例:
使用 Spring Data JPA 和 Hibernate 作为 JPA 提供程序。

实体:

public class Blog{
   ...
   @ManyToMany(fetch = FetchType.LAZY) //default is LAZY in ManyToMany
    @JoinTable(name="blog_tag",
        joinColumns = @JoinColumn(name = "blog_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id"))
    @OrderBy //order by tag id
    private Set<Tag> tags = new HashSet<>();

    //2 utility methods in owner side
    public void addTag(Tag tag){
        tags.add(tag);
        tag.getBlogs().add(this);
    }
    public void removeTag(Tag tag){
        tags.remove(tag);
        tag.getBlogs().remove(this);
    }
    
    //override equals & hashcode 

}


public class Tag {
    ...
    @ManyToMany(mappedBy = "tags")
    private Set<Blog> blogs = new HashSet<>();

    //override equals & hashcode 
}

现在假设您想获取包含标签项的博客:

存储库:

@Repository
public interface BlogRepository extends JpaRepository<Blog, Long> {
    @Query("select b from Blog b join fetch b.tags where b.name = :name")
    Blog getBlog(@Param("name") String blogName);
}

服务:

public interface BlogService {
    Blog getBlog(String blogName);
}

@Service
public class BlogServiceImpl implements BlogService{

    @Autowired
    private BlogRepository blogRepository;

    @Override
    public Blog getBlog(String blogName) {
        return blogRepository.getBlog(blogName);
    }

}


1
你只需要在Person和Movie之间进行一次JOIN操作。由于Hibernate抽象了中间表的存在,所以你不必担心它。
因此,使用Spring Data Repository:
class PersonRepository extends CrudRepository<Person, Long> {

    List<Person> findByMoviesActor();
}

使用Jpql:
SELECT person FROM Person person JOIN person.moviesActor movie

1

由于您正在使用Fetch类型懒惰,因此需要使用join fetch来获取moviesActor。

您可以使用Spring Data中的JPQL。我尚未测试以下查询,但应该可以工作。

public interface PersonRepository extends JpaRepository<Person, Long> { //Long if Person.id is of type Long

  @Query("SELECT p FROM Person p LEFT JOIN FETCH p.moviesActor WHERE size(p.moviesActor) > 0");
  List<Person> findActors1();

  // Or

  @Query("SELECT p FROM Person p JOIN FETCH p.moviesActor");
  List<Person> findActors2();

}

关于jpql size()运算符的更多信息,请参见https://www.thoughts-on-java.org/jpql/


1
您可以直接使用 join:
@Query("SELECT p FROM Person p  JOIN  p.moviesActor movie");

查找拥有电影的人列表


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接