代码之家  ›  专栏  ›  技术社区  ›  Senio Vak

Spring数据JPA-多对多查询

  •  0
  • Senio Vak  · 技术社区  · 6 年前

    我有两个人和电影。

    @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<>();
    }
    

    有许多对许多的关系,所以有新的表演员电影来保持它。我怎样才能让每个人都有自己的电影呢?所以我想要达到的是让每个人都在演员席上。我尝试使用springdatajpa,但找不到正确的查询。

    3 回复  |  直到 6 年前
        1
  •  2
  •   Ghasem Sadeghi    4 年前

    实体关系最佳实践:

    1. 始终使用 fetch = FetchType.LAZY .
    2. 当你想获取关系的另一面时,使用 JOIN FETCH 查询。
      这就解决了 LazyInitializationException
    3. spring.jpa.open-in-view=false

    例子:
    由Spring提供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);
        }
    
    }
    
    
        2
  •  1
  •   Carlos Nantes    6 年前

    您可以对spring数据使用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();
    
    }
    

    https://www.thoughts-on-java.org/jpql/

        3
  •  1
  •   AdagioDev    5 年前

    您可以直接使用join:

    @Query("SELECT p FROM Person p  JOIN  p.moviesActor movie");
    

        4
  •  -1
  •   Dherik    6 年前

    你只需要一个 JOIN 在人和电影之间。当Hibernate抽象出中间表的存在时,您不必担心它。

    因此,使用Spring数据存储库:

    class PersonRepository extends CrudRepository<Person, Long> {
    
        List<Person> findByMoviesActor();
    }
    

    使用Jpql:

    SELECT person FROM Person person JOIN person.moviesActor movie