1. ホーム
  2. java

[解決済み] Spring Data JPAにおけるFetchModeの動作について

2022-10-31 01:09:58

質問

私のプロジェクトでは、3つのモデルオブジェクトの間に関係があります(投稿の最後にあるモデルとリポジトリのスニペット。

私が PlaceRepository.findById を呼び出すと、3つのセレクトクエリが実行されます。

("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

それは(私にとっては)かなり珍しい動作です。Hibernateのドキュメントを読んだ限りでは、常にJOINクエリを使用するはずです。クエリに違いはありません。 FetchType.LAZYFetchType.EAGERPlace クラス(SELECT を追加したクエリ)でも、同じように City クラスの場合 FetchType.LAZY に変更されました。 FetchType.EAGER (に変更されます(JOINを使ったクエリ)。

私が CityRepository.findById を抑えると、2つのselectが発生します。

  1. SELECT * FROM city c where id = arg
  2. SELECT * 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")
    private User author;

    @Fetch(FetchMode.JOIN)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "area_city_id")
    private City city;
    //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")
    private State state;
    //getters and setters
}

リポジトリです。

プレイスレポジトリ

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

どのように解決するのですか?

Spring DataはFetchModeを無視していると思うのですが。私はいつも @NamedEntityGraph@EntityGraph アノテーションは、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);

}

ドキュメントを確認する ここで