我有两个实体,一个实体“电影”和一个实体“剪辑”每个剪辑属于一个电影,一个电影可以有多个剪辑。
我的代码看起来像:
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;
正在生成表,每个Clip都有一个列“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-bidirectional-list.html
“要将双向一个映射到多个,一对多一侧作为拥有方,您必须删除mappedBy元素并将多个@JoinColumn设置为可插入且可更新为false。此解决方案显然未进行优化并会产生一些额外的UPDATE语句。“
当我要求电影时,我得到以下答案:
{“id”:1,“version”:1,“name”:“MGS Walkthrough”,“filename”:“video.mp4”,“movieCategories”:[{“id”:1,“version”:1, “名称”:“演练”}],“剪辑”:[],“说明”:“预告片zu mgs4”}
条目“剪辑”仍然出现。这仍然是错误的解决方案还是我必须忍受这个?
我遇到了完全相同的问题。我尝试了引用段落中的解决方案,它对我不起作用。
我所做的是在Clip类中为getMovie()返回null,然后无限循环问题就消失了。以JSON格式返回的数据看起来像{“movieId”:1 ... clips:[“clipId”:1,“movie”:“null”,..]}。
如果您还想在JSON中进一步删除movie属性,请将类级注释添加到Clip类@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
Jackson feature: prevent serialization of nulls, default values
更新:我发现的更简单的方法是在Clip类中删除电影的getter。
解:
使用
@JsonManagedReference
注释实例化的第一个对象
@JsonBackReference
注释为第二个对象实例化
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
。
我建议只返回一个DTO对象,而不是返回一个Entity对象。您可以使用结果转换器直接从Hibernate查询/条件结果中获取一个。
我遇到了这种情况的主要问题。
当你获得电影时,系统会加载一个关系剪辑列表,但是在CLip类中你有一个属性Movie,当你有这个属性的getter时,系统会再次加载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 }
例如:你得到电影01,这部电影与剪辑01和剪辑02有关系,当电影01的系统加载数据时,它也通过你的getter方法获取Clip 01和Clip 02的数据。
但是在Clip类中,你还有属性Movie和getter getMovie()。所以当系统查找CLip 01的数据时,它也会获得关系Movie的数据,在这种情况下是Movie 01 ...而Movie 01将获得CLip 01 =>的数据所以这正是我们为什么有一个循环的原因
所以这种情况的确切解决方案是Clip.java中的Delete Getter Method getMovie()我们不需要使用这些信息
首先,让我向您展示为什么将获取类型设置为惰性无效。当你尝试序列化你的pojo时,你的序列化器(也许是jackson)会调用这个pojo的每个getter,并使用getter的返回值作为json数据中的属性。因此它显式调用getter,它调用hibernate来加载你的相关实体(Clip的电影和Movie的剪辑)。所以你需要使用@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应用程序的最佳实践。
Dino Tw说的简单方法:
从getMovie()
类中删除Clip
函数。
这将帮助您检索Clip
实体/表格中由Movie
关联的每个movie_id
的Clip
列表。
@Entity
@Table(name="Movie")
public class Movie implements Serializable{
@OneToMany(mappedBy="movie",targetEntity=Clip.class,cascade=CascadeType.ALL,
fetch=FetchType.EAGER)
private Set<Clip> clips = new HashSet<Clip>();
}
@Entity
@Table(name="Clip")
public class Clip implements Serializable{
@ManyToOne
@JoinColumn(name="movie_id")
@JsonIgnore
private Movie movie;
}