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

时间:2013-05-16 02:10:07

标签: json hibernate one-to-many hibernate-onetomany

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

我的代码如下:

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

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

9 个答案:

答案 0 :(得分:15)

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

我所做的是在Clip类中为getMovie()返回null,然后无限循环问题就消失了。以JSON格式返回的数据看起来像{“movieId”:1 ... clips:[“clipId”:1,“movie”:“null”,..]}。

如果您还想在JSON中进一步删除movie属性,请将类级注释添加到Clip类 @JsonSerialize(包括= JsonSerialize.Inclusion.NON_NULL)

Jackson feature: prevent serialization of nulls, default values

更新: 我找到的更简单的方法是在Clip类中删除电影的getter。

答案 1 :(得分:7)

解决方案:

使用

实例化的第一个对象的

@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 :(得分:2)

正如您所说“条目剪辑仍然显示”。

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

获取Movie时,系统将加载关系剪辑的列表,但是在CLip类中,您具有属性Movie,当拥有此属性的吸气剂时,系统将再次加载Movie。

data <- structure(list(pitch_1 = c("429721-CU", "114849-FC", "430599-FF", 
"458567-FF", "435261-CU", "425629-CU"), pitch_2 = c("493247-SI", 
"493247-SI", "493247-SI", "493247-SI", "493247-SI", "493247-SI"
), euclid_dist = c(2.53, 3.52, 3.49, 2.59, 3.1, 2.14), rank = c(15L, 
6L, 14L, 27L, 8L, 17L)), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6"))

例如: 您得到电影01,该电影与剪辑01和剪辑02有关系,当系统加载电影01的数据时,它也通过您的getter方法获取剪辑01和剪辑02的数据。

但是在Clip类中,您还具有属性Movie和一个getter getMovie()。因此,当系统查找CLip 01的数据时,它也获得了与Movie相关的数据,在这种情况下为Movie 01 ...,而Movie 01将获得CLip 01的数据=>因此,这正是我们产生循环的原因

因此针对这种情况的确切解决方案是 在Clip.java中删除Getter方法getMovie() 我们不需要使用此信息

答案 5 :(得分:0)

首先,让我向您展示为什么将fetch type设置为lazy并没有帮助。 当您尝试序列化pojo时,序列化程序(也许是jackson)会调用此pojo的每个getter,并将getter的返回值用作json数据中的属性。因此,它将显式调用getter,后者将调用hibernate来加载关联的实体(Clip的movie和Movie的clip)。 因此,您需要使用@JsonIgnoreProperties摆脱这个奇怪的无限循环,代码如下:

<?php
    global $wp_query;
    $author = $wp_query->get_queried_object();

    // author id
    $author_id = get_the_author_meta('ID');

    // vars
    $test = get_field('test', 'user_'. $author_id ); ?>

    // None of these work   
    <?= ( $test )? '<h1>' . $test .'</h1>' : '';?>
    <h1><?php echo $test; ?></h1>

    // This works
    <h1 class="page-title page-title__author"><?php echo $author->display_name; ?></h1>

那样,您会发现剪辑json对象中的嵌套电影在电影内部没有“剪辑”,并且电影中的嵌套剪辑也没有“电影”子代。

我想这是解决此问题的最佳方法,也是开发Java Web应用程序的最佳实践。

答案 6 :(得分:0)

基本上,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/bidirectional-relationship-in-json

import com.fasterxml.jackson.annotation.ObjectIdGenerators;

答案 7 :(得分:-1)

Dino Tw说的简单方法:

getMovie()类中删除Clip函数。

这将有助于您检索Clip实体/表格中Movie关联的每个movie_id的{​​{1}}列表。

答案 8 :(得分:-3)

需要在子类中添加@JsonIgnore以避免此类异常。注意不要在父类中添加此批注

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