FetchMode如何在Spring Data JPA中工作 [英] How does the FetchMode work in Spring Data JPA

查看:109
本文介绍了FetchMode如何在Spring Data JPA中工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的项目中有三个模型对象之间存在关系(模型和存储库代码片段在结尾处)。



当我调用 PlaceRepository.findById 它会触发三个select查询:

(sql)


  1. SELECT * FROM place p where id = arg

  2. SELECT * FROM用户u其中u.id = place.user.id

  3. SELECT * FROM city c c上的LEFT OUTER JOIN状态s .woj_id = s.id其中c.id = place.city.id

这是非常不寻常的行为(对我来说),据我在阅读Hibernate文档后可以知道它应该总是使用JOIN查询,当 FetchType.LAZY 改变为<$时,查询没有区别在$ > Place 类(使用额外的SELECT进行查询)中使用c $ c> FetchType.EAGER ,对于 City FetchType.LAZY 更改为 FetchType.EAGER (使用JOIN查询)时, / p>

当我使用 CityRepository.findById 抑制触发两个选择时:




  • SELECT * FROM city c其中id = arg * FROM state s where id = city.state.id

  • 我的目标是拥有一个山姆在所有情况下的行为(总是JOIN或SELECT,尽管JOIN首选)。



    模型定义:



     @Entity 
    @Table(name =place)
    public class Place extends Identified {

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name =id_user_author)
    私人用户作者;

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name =area_city_id)
    私人城市城市;
    // getters and setters
    }

    城市:

      @Entity 
    @Table(name =area_city)
    public class City extends Identified {

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name =area_woj_id)
    私有状态;
    // getters and setters
    }

    存储库:



    PlaceRepository

      public interface PlaceRepository扩展JpaRepository< Place,Long>,PlaceRepositoryCustom {
    Place findById(int id);
    }

    UserRepository:

      public interface UserRepository扩展JpaRepository< User,Long> {
    列表<用户>找到所有();
    用户findById(int id);
    }

    CityRepository:

      public interface CityRepository扩展JpaRepository< City,Long> ;, CityRepositoryCustom {
    City findById(int id);


    解决方案

    我认为Spring Data忽略FetchMode。使用Spring Data时,我总是使用 @NamedEntityGraph @EntityGraph 注解

      @Entity 
    @NamedEntityGraph(name =GroupInfo.detail,
    attributeNodes = @NamedAttributeNode(members))
    公共类GroupInfo {

    //默认获取模式是懒惰的。
    @ManyToMany
    列表< GroupMember> members = new ArrayList< GroupMember>();

    ...
    }

    @Repository
    公共接口GroupRepository扩展CrudRepository< GroupInfo,String> {

    @EntityGraph(value =GroupInfo.detail,type = EntityGraphType.LOAD)
    GroupInfo getByGroupName(String name);


    检查文档 here


    I do have a relation between three model object in my project (model and repository snippets in the end of the post.

    When I call PlaceRepository.findById it does fire three select queries:

    ("sql")

    1. SELECT * FROM place p where id = arg
    2. SELECT * FROM user u where u.id = place.user.id
    3. SELECT * FROM city c LEFT OUTER JOIN state s on c.woj_id = s.id where c.id = place.city.id

    That's rather unusual behavior (for me). As far as I can tell after reading Hibernate documentation it should always use JOIN queries. There is no difference in the queries when FetchType.LAZY changed to FetchType.EAGER in the Place class (query with additional SELECT), the same for the City class when FetchType.LAZY changed to FetchType.EAGER (query with JOIN).

    When I use CityRepository.findById suppressing fires two selects:

    1. SELECT * FROM city c where id = arg
    2. SELECT * FROM state s where id = city.state.id

    My goal is to have a the sam behavior in all situations (either always JOIN or SELECT, JOIN preferred though).

    Model definitions:

    Place:

    @Entity
    @Table(name = "place")
    public class Place extends Identified {
    
        @Fetch(FetchMode.JOIN)
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "id_user_author")
        private User author;
    
        @Fetch(FetchMode.JOIN)
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "area_city_id")
        private City city;
        //getters and setters
    }
    

    City:

    @Entity
    @Table(name = "area_city")
    public class City extends Identified {
    
        @Fetch(FetchMode.JOIN)
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "area_woj_id")
        private State state;
        //getters and setters
    }
    

    Repositories:

    PlaceRepository

    public interface PlaceRepository extends JpaRepository<Place, Long>, PlaceRepositoryCustom {
        Place findById(int id);
    }
    

    UserRepository:

    public interface UserRepository extends JpaRepository<User, Long> {
            List<User> findAll();
        User findById(int id);
    }
    

    CityRepository:

    public interface CityRepository extends JpaRepository<City, Long>, CityRepositoryCustom {    
        City findById(int id);
    }
    

    解决方案

    I think that Spring Data ignores the FetchMode. I always use the @NamedEntityGraph and @EntityGraph annotations when working with Spring Data

    @Entity
    @NamedEntityGraph(name = "GroupInfo.detail",
      attributeNodes = @NamedAttributeNode("members"))
    public class GroupInfo {
    
      // default fetch mode is lazy.
      @ManyToMany
      List<GroupMember> members = new ArrayList<GroupMember>();
    
      …
    }
    
    @Repository
    public interface GroupRepository extends CrudRepository<GroupInfo, String> {
    
      @EntityGraph(value = "GroupInfo.detail", type = EntityGraphType.LOAD)
      GroupInfo getByGroupName(String name);
    
    }
    

    Check the documentation here

    这篇关于FetchMode如何在Spring Data JPA中工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆