Hibernate @OneToMany关系导致JSON结果中的无限循环或空条目

问题描述 投票:12回答:8

我有两个实体,一个实体“电影”和一个实体“剪辑”每个剪辑属于一个电影,一个电影可以有多个剪辑。

我的代码看起来像:

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”}

条目“剪辑”仍然出现。这仍然是错误的解决方案还是我必须忍受这个?

json hibernate one-to-many hibernate-onetomany
8个回答
15
投票

我遇到了完全相同的问题。我尝试了引用段落中的解决方案,它对我不起作用。

我所做的是在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。


9
投票

解:

使用

@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;

2
投票

正如你所说“条目剪辑仍然出现”。

要避免db响应中的关系数据将fetch = FetchType.EAGER更改为fetch = FetchType.Lazy


1
投票

我建议只返回一个DTO对象,而不是返回一个Entity对象。您可以使用结果转换器直接从Hibernate查询/条件结果中获取一个。


1
投票

我遇到了这种情况的主要问题。

当你获得电影时,系统会加载一个关系剪辑列表,但是在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()我们不需要使用这些信息


0
投票

首先,让我向您展示为什么将获取类型设置为惰性无效。当你尝试序列化你的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应用程序的最佳实践。


-1
投票

Dino Tw说的简单方法:

getMovie()类中删除Clip函数。

这将帮助您检索Clip实体/表格中由Movie关联的每个movie_idClip列表。


-3
投票

Need to add @JsonIgnore in child class to avoid such exception. Be careful not to add this annotation in Parent class

@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;
}
© www.soinside.com 2019 - 2024. All rights reserved.