2つのエンティティがあります。エンティティ「movie」とエンティティ「Clip」です。各クリップは1つのムービーに属し、ムービーには複数のクリップを含めることができます。
私のコードは次のようになります:
Movie.Java
@OneToMany(mappedBy = "movie", targetEntity = Clip.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Clip> clips = new HashSet<Clip>();
Clip.Java
@ManyToOne
@JoinColumn(name="movie_id")
private Movie movie;
テーブルが生成されており、各クリップには「movie_id」列がありますが、これにより、データを要求しているときにアプリケーションが無限ループに陥ります。
@Path("/{id:[0-9][0-9]*}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Movie lookupMovieById(@PathParam("id") long id) {
return em.find(Movie.class, id);
}
result:
{"id":1,"version":1,"name":"MGS Walkthrough","filename":"video.mp4","movieCategories":[{"id":1,"version":1,"name":"Walkthrough"}],"clips":[{"id":1,"version":1,"name":"MGS Walkthrough P1","keywords":null,"movie":{"id":1,"version":1,"name":"MGS Walkthrough","filename":"video.mp4","movieCategories":[{"id":1,"version":1,"name":"Walkthrough"}],"clips":[{"id":1,"version":1,"name":"MGS Walkthrough P1","keywords":null,"movie":{"id":1,"version":1,"name":"MGS Walkthrough","filename":"video.mp4","movieCategories":[{"id":1,"version":1,"name":"Walkthrough"}],"clips":[{"id":1,"version":1,"name":"M...
クリップをリクエストしたときも同じ結果です。
@ManyToMany関係に変更しても、そのような問題は発生しませんが、ここで必要なのはそれではありません。手伝って頂けますか? fetchTypeをLazyに設定しても機能しませんでした。
編集:現在のJBoss開発スタジオを使用しています
編集:
私はこの記事を読んでこれを「解決」しました:
http://blog.jonasbandi.net/2009/02/help-needed-mapping-bidirection-list.html
「1対多の側を所有側として双方向の1対多をマッピングするには、mappedBy要素を削除し、manyを1に設定して挿入可能および更新可能としてfalseにする必要があります。このソリューションは明らかに最適化されていませんそして、いくつかの追加のUPDATEステートメントを生成します。」
映画をリクエストすると、次の答えが返ってきます。
{"id":1、 "version":1、 "name": "MGS Walkthrough"、 "filename": "video.mp4"、 "movieCategories":[{"id":1、 "version":1、 "name": "Walkthrough"}]、 "clips":[]、 "description": "Trailer zu mgs4"}
エントリ「クリップ」は引き続き表示されます。これはまだ間違った解決策ですか、それとも私はこれと一緒に暮らす必要がありますか?
私はまったく同じ問題に遭遇しました。引用した段落の解決策を試しましたが、うまくいきませんでした。
私がしたことは、ClipクラスのgetMovie()に対してnullを返すことです。そうすれば、無限ループの問題はなくなります。 JSON形式で返されるデータは、{"movieId":1 ... Clips:["clipId":1、 "movie": "null"、..]}のようになります。
JSONのmovieプロパティもさらに削除する場合は、クラスレベルのアノテーションをClipクラス@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)に追加します。
更新:私が見つけたより簡単な方法は、Clipクラスのムービーのゲッターを削除することです。
解決:
使用する
@JsonManagedReference
インスタンス化された最初のオブジェクトの注釈
@JsonBackReference
インスタンス化された2番目のオブジェクトの注釈
Movie.Java
@JsonManagedReference
@OneToMany(mappedBy = "movie", targetEntity = Clip.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Clip> clips = new HashSet<Clip>();
Clip.Java
@JsonBackReference
@ManyToOne
@JoinColumn(name="movie_id")
private Movie movie;
あなたが言っているように、「エントリークリップはまだ表示されます」。
Db応答の関係データを回避するには、fetch = FetchType.EAGER
をfetch = FetchType.Lazy
に変更します。
Entityオブジェクトを返す代わりに、必要なデータのみを含むDTOオブジェクトを返すことをお勧めします。結果トランスフォーマーを使用して、Hibernateクエリ/基準の結果から直接取得できます。
まず、フェッチタイプをレイジーに設定しても効果がない理由を説明します。 pojoをシリアル化しようとすると、シリアライザー(おそらくjackson)はこのpojoのすべてのgetterを呼び出し、getterの戻り値をjsonデータのプロパティとして使用します。したがって、getterを明示的に呼び出し、hibernateを呼び出して、関連付けられたエンティティ(Clipの場合はmovie、Movieの場合はclips)をロードします。したがって、@ JsonIgnorePropertiesを使用して、この奇妙な無限ループを取り除く必要があります。コードは次のようになります。
Clip.Java
@ManyToOne
@JoinColumn(name="movie_id")
@JsonIgnoreProperties("clips")
private Movie movie;
Movie.Java
@OneToMany(mappedBy = "movie", targetEntity = Clip.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JsonIgnoreProperties("movie")
private Set<Clip> clips = new HashSet<Clip>();
そうすれば、クリップjsonオブジェクト内のネストされたムービーには、ムービー内に「クリップ」がなく、ムービー内のネストされたクリップにも「ムービー」の子がありません。
これがこの問題に対処するための最良の方法であり、Java Webアプリを開発するためのベストプラクティスでもあると思います。
私はこの状況の主な問題を抱えています。
Movieを取得すると、システムはリレーションクリップのリストをロードしますが、CLipクラスにはプロパティMovieがあり、このプロパティのゲッターがあると、システムは再びMovieをロードします。
Movie.Java
@OneToMany(mappedBy = "movie", targetEntity = Clip.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Clip> clips = new HashSet<Clip>();
//the below getter will look for data of related Clip
public Set<Clip> getClips(){ return this.clips}
Clip.Java
@ManyToOne
@JoinColumn(name="movie_id")
private Movie movie;
//the below getter will look for related Movie again
public Movie getMovie() { return this.movie }
例:Movie 01を取得すると、このムービーはClip01およびClip02と関係があり、Movie 01のシステムロードデータが、getterメソッドを介してClip01およびClip02のデータもフェッチします。
ただし、Clipクラスには、プロパティMovieとgetter getMovie()もあります。したがって、システムがCLip 01のデータを検索すると、関係Movieのデータも取得します。この状況ではMovie 01 ...およびMovie01はCLip01のデータを取得します=>したがって、これがループがある理由です。
したがって、この状況の正確な解決策はClip.JavaのGetterメソッドgetMovie()を削除この情報を使用する必要はありません。
Dino Twが言ったように簡単な方法:
Clip
クラスからgetMovie()
関数を削除します。
これは、Clip
エンティティ/テーブル内のmovie_id
によって関連付けられている各Movie
のClip
リストを取得するのに役立ちます。
基本的に、JsonIgnoreまたはJsonBackrefrencingは、一方の端からリンクを削除します。
適切なリンクと正しいJson出力を行うには、以下のコードスニペットに従ってください:-
@Entity
@Table(name="Movie")
public class Movie{
@JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, property="@id")
@OneToMany(mappedBy="movie",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private Set<Clip> clips = new HashSet<Clip>();
}
@Entity
@Table(name="Clip")
public class Clip{
@JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, property="@id")
@ManyToOne
@JoinColumn(name="movie_id")
@JsonIgnore
private Movie movie;
}
詳細については、以下のリンクを参照してください: https://www.toptal.com/javascript/bidirection-relationship-in-json
import com.fasterxml.jackson.annotation.ObjectIdGenerators;