web-dev-qa-db-ja.com

Spring Data JPA-無限再帰を伴う双方向関係

まず、ここに私のエンティティがあります。

プレイヤー

@Entity
@JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, 
property="id")
public class Player {

    // other fields

    @ManyToOne
    @JoinColumn(name = "pla_fk_n_teamId")
    private Team team;

    // methods

}

チーム

@Entity
@JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, 
property="id")
public class Team {

    // other fields

    @OneToMany(mappedBy = "team")
    private List<Player> members;

    // methods

}

多くのトピックがすでに述べられているように、Jacksonを使用すると、WebServiceのStackOverflowExeptionをさまざまな方法で回避できます。

これはすばらしいことですが、JPAはシリアル化の前に、別のエンティティへの無限再帰を使用してエンティティを構築します。これは醜い問題であり、リクエストにはかなり時間がかかります。このスクリーンショットを確認してください: IntelliJ debugger

それを修正する方法はありますか?エンドポイントによって異なる結果が必要であることを知っている。例:

  • エンドポイント/ teams/{id}=> Team = {id ...、members = [Player = {id ...、team = null}]}
  • エンドポイント/ members/{id}=>プレーヤー= {id ...、チーム= {id ...、members = null}}

ありがとうございました!

編集:多分質問は私が得た答えを与えることは非常に明確ではないので、私はより正確にしようとします。

Jackson(@ JSONIgnore、@ JsonManagedReference/@ JSONBackReferenceなど)を使用するか、DTOへのマッピングを行うことで、無限再帰を防ぐことができることを知っています。私がまだ目にする問題はこれです。上記の両方がポストクエリ処理です。 Spring JPAが返すオブジェクトは、依然として(たとえば)チームであり、プレーヤーのリストが含まれている、チームが含まれている、プレーヤーのリストが含まれている、などです。

JPAまたはリポジトリ(または何か)にエンティティ内のエンティティを何度もバインドしないように指示する方法があるかどうか知りたいですか?

8

これが私のプロジェクトでこの問題を処理する方法です。

私は、フルオブジェクトとライトオブジェクトの2つのバージョンで実装されたデータ転送オブジェクトの概念を使用しました。

参照エンティティを含むオブジェクトをListとしてDto(シリアル化可能な値のみを保持するデータ転送オブジェクト)として定義し、参照エンティティのないオブジェクトをInfoとして定義します。

Infoオブジェクトは、エンティティ自体に関する情報のみを保持し、関係に関する情報は保持しません。

ここで、REST APIを介してDtoオブジェクトを提供する場合、参照用にInfoオブジェクトを配置するだけです。

私がPlayerDtoGET /players/1よりも配信しているとしましょう:

public class PlayerDto{
   private String playerName;
   private String playercountry;
   private TeamInfo;
}

TeamInfoオブジェクトは次のようになります

public class TeamInfo {
    private String teamName;
    private String teamColor;
}

TeamDtoと比較

public class TeamDto{
    private String teamName;
    private String teamColor;
    private List<PlayerInfo> players;
}

これにより、無限のシリアル化が回避され、残りのリソースが論理的に終了します。そうしないと、GET /player/1/team/player/1/teamを実行できるはずです。

さらに、この概念では、実際のエンティティオブジェクトをインターフェースに渡さないため、データレイヤーとクライアントレイヤー(この場合はREST API))が明確に分離されています。このために、サービスレイヤー内の実際のエンティティをDtoまたはInfoに設定します。これには http://modelmapper.org/ を使用します。メソッド呼び出し)。

また、参照されているすべてのエンティティをフェッチしますlazily。エンティティを取得してトランザクションスコープ内で実行するためにDtoに変換するサービスメソッド。これはとにかく良い方法です。

遅延フェッチ

エンティティを遅延フェッチするようにJPAに指示するには、フェッチタイプを定義してリレーションシップアノテーションを変更します。これのデフォルト値はfetch = FetchType.EAGERであり、状況によっては問題があります。そのため、fetch = FetchType.LAZYに変更する必要があります

public class TeamEntity {

    @OneToMany(mappedBy = "team",fetch = FetchType.LAZY)
    private List<PlayerEntity> members;
}

同様にPlayer

public class PlayerEntity {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pla_fk_n_teamId")
    private TeamEntity team;
}

サービスレイヤーからリポジトリメソッドを呼び出す場合、これが@Transactionalスコープ内で発生していることが重要です。そうしないと、遅延参照されたエンティティを取得できません。これは次のようになります。

 @Transactional(readOnly = true)
public TeamDto getTeamByName(String teamName){
    TeamEntity entity= teamRepository.getTeamByName(teamName);
    return modelMapper.map(entity,TeamDto.class);
}
6
Herr Derb

@ JsonIgnoreProperties アノテーションを使用して、次のように無限ループを回避できます。

@JsonIgnoreProperties("members")
private Team team;

またはこのように:

@JsonIgnoreProperties("team")
private List<Player> members;

または両方。

4
Cepr0

私の場合、OneToMany-ManyToOne(双方向)の関係が必要ないことを理解して、これを解決しました。

このような何かが私の問題を修正しました

// Team Class:
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Player> members = new HashSet<Player>();

// Player Class:
// - I removed the 3 lines

ここに他の例とのリンクがあります: https://github.com/thombergs/code-examples/tree/master/spring-data/spring-data-rest-associations/src/main/Java/com/example/demo

プロジェクトLombokでも同じ問題が発生します。 @ ToString@ EqualsAndHashCodeを試してそれを修正しました:

例えば.

@Data
@Entity

@EqualsAndHashCode(exclude = { "members"}) // This,
@ToString(exclude = { "members"}) // and this

public class Team implements Serializable {

// ...


また、ループ防止アノテーションに関する有用なガイドもあります
https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion

1
user9869932