Spring JPA一对多无限递归

huangapple go评论80阅读模式
英文:

Spring JPA One To Many Infinite Recursion

问题

以下是您提供的代码的翻译部分:

这是我的 Posts 类

@Data
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
public class Posts {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "post_id")
    private Long post_id;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private Users user;

    @Column(name = "description")
    private String description;

    @Column(name="images")
    private String images;

    @Column(name="tags")
    private String tags;

    @OneToMany(
        fetch = FetchType.LAZY,
        mappedBy = "post",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    @JsonIgnoreProperties(value = { "comments", "hibernateLazyInitializer", "handler" }, allowSetters = true)
    //@JsonManagedReference
    private List<Comments> comments;

    @LastModifiedDate
    @Column(name = "last_updated")
    private Date lastUpdated;

    public void addComments(Comments comment) {
        this.comments.add(comment);
    }
}

这是我的 PostDTO 类

@Data
public class PostDTO {

    private Long post_id;
    private UserDTO user;
    private String description;
    private String images;
    private String tags;
    private List<CommentsDTO> comments;
    private Date lastUpdated;
}

这是我的 Comments 类

@Data
@Entity
@Table(name = "comments")
@EntityListeners(AuditingEntityListener.class)
public class Comments {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="comment_id")
    private Long comment_id;

    @OneToOne
    @JoinColumn(name = "user_id")
    private Users user;

    @Column(name = "description")
    private String description;

    @Column(name="images")
    private String images;

    @ManyToOne
    @JoinColumn(name ="post_id" , nullable = false)
    @JsonIgnoreProperties(value = { "post", "hibernateLazyInitializer", "handler" }, allowSetters = true)
    //@JsonBackReference
    private Posts post;

    @Column(name="last_updated")
    @LastModifiedDate
    private Date lastUpdated;
}

这是我的 CommentsDTO 类

@Data
public class CommentsDTO {

    private Long comment_id;
    private UserDTO user;
    private String description;
    private PostDTO post;
    private String images;
    private Date lastUpdated;
}

这是我的 REST Controller

@GetMapping
public @ResponseBody ResponseEntity<List<PostDTO>> getAll() throws Exception {
    return new ResponseEntity<List<PostDTO>>(service.getAll(), HttpStatus.OK);
}

这是我的 service

public List<PostDTO> getAll() throws Exception  {
    return repo.findAll()
               .stream()
               .map(this::convert)
               .collect(Collectors.toList());
}

private PostDTO convert(Posts e) {
    return  mapper.map(e, PostDTO.class);
}

希望这对您有所帮助。如果您有任何问题,请随时问我。

英文:

im trying to return to a JPA data (converted to DTO, ofcourse) where it has a @OneToMany and @ManyToOne bidirectional relationship. Im currently apply thing fix. The problem is that the output is recusrive. comments has post has comments then has posts (comments -> post -> coments -> so on..).

I only wnat to have something like this

{
	&quot;post_id&quot;: 1
    &quot;user&quot;: {
        // user data
    },
    &quot;description&quot;: &quot;some description&quot;,
    &quot;images&quot;: &quot;{images,images}&quot;,
    &quot;tags&quot;: &quot;{tags, tags}&quot;,
	&quot;comments&quot;: [
	 {
		//some comments data
		
	 },
	 {
		//some comments data
	 }
	]
    &quot;lastUpdated&quot;: &quot;2020-04-08T14:23:18.000+00:00&quot;
}

Here are my code

This is my Posts.class

@Data
@Entity
@Table(name = &quot;posts&quot;)
@EntityListeners(AuditingEntityListener.class)
public class Posts {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = &quot;post_id&quot;)
	private Long post_id;

	@ManyToOne
	@JoinColumn(name = &quot;user_id&quot;, nullable = false)
	private Users user;
	
	@Column(name = &quot;description&quot;)
	private String description;
	
	@Column(name=&quot;images&quot;)
	private String images;
	
	@Column(name=&quot;tags&quot;)
	private String tags;
	
	@OneToMany(
		fetch = FetchType.LAZY,
		mappedBy = &quot;post&quot;,
		cascade = CascadeType.ALL,
		orphanRemoval = true
	)
	@JsonIgnoreProperties(value = { &quot;comments&quot; ,&quot;hibernateLazyInitializer&quot;, &quot;handler&quot; }, allowSetters = true)
	//@JsonManagedReference
	private List&lt;Comments&gt; comments;
	
		
	@LastModifiedDate
	@Column(name = &quot;last_updated&quot;)
	private Date lastUpdated;
	
	
	public void addComments(Comments comment) {
		this.comments.add(comment);
	}
}

Here is my PostDTO.class

@Data
public class PostDTO {

	private Long post_id;
	private UserDTO user;
	private String description;
	private String images;
	private String tags;
	private List&lt;CommentsDTO&gt; comments;
	private Date lastUpdated;
	

}

This is my Comments.class

@Data
@Entity
@Table(name = &quot;comments&quot;)
@EntityListeners(AuditingEntityListener.class)
public class Comments {
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name=&quot;comment_id&quot;)
	private Long comment_id;
	
	@OneToOne
	@JoinColumn(name = &quot;user_id&quot;)
	private Users user;

	@Column(name = &quot;description&quot;)
	private String description;
	
	@Column(name=&quot;images&quot;)
	private String images;
	
	@ManyToOne
	@JoinColumn(name =&quot;post_id&quot; , nullable = false)
	@JsonIgnoreProperties(value = { &quot;post&quot; ,&quot;hibernateLazyInitializer&quot;, &quot;handler&quot; }, allowSetters = true)
	//@JsonBackReference
	private Posts post;
	
	@Column(name=&quot;last_updated&quot;)
	@LastModifiedDate
	private Date lastUpdated;
	
}

Here is my CommentsDTO.class

@Data
public class CommentsDTO {
	
	private Long comment_id;
		
	private UserDTO user;
	
	private String description;
	
	private PostDTO post;
	
	private String images;
	
	private Date lastUpdated;
}

Here is my REST Controller

@GetMapping
public @ResponseBody ResponseEntity&lt;List&lt;PostDTO&gt;&gt;  getAll() throws Exception {
	
	return new ResponseEntity&lt;List&lt;PostDTO&gt;&gt;(service.getAll(), HttpStatus.OK);
}

Here is my service

public List&lt;PostDTO&gt; getAll() throws Exception  {
	return repo.findAll()
			   .stream()
			   .map(this::convert)
			   .collect(Collectors.toList());
}

private PostDTO convert(Posts e) {
	return  mapper.map(e, PostDTO.class);
}

Hope someone can shed light on my issue. Kinda lost as of this time.

答案1

得分: 1

问题在于当你将 Post 转换为 PostDTO 时,通过使用 ModelMapper,它会调用 Post 的所有字段的 getter 方法来为 PostDTO 设置值。因此,对于这个语句 mapper.map(e, PostDTO.class),会发生递归调用。

所以,只需从 CommentDTO 中移除 private PostDTO post 字段,
然后 ModelMapper 就不会尝试设置 PostDTO->comment->post 字段。
在DTO中不需要双向关系。DTO 完全是关于你想在响应中展示什么内容。

英文:

Problem is when you convert Post into PostDTO then by using ModelMapper it calls all field's getter of Post for PostDTO. So this happened recursively for this
mapper.map(e, PostDTO.class)

So, just remove private PostDTO post from CommentDTO ,
then modelmapper don't try to set PostDTO->comment-> post field.
And you don't need bidirectional relation in DTO. DTO is all about what you want to show in response.

答案2

得分: 0

你正在错误的类上打破了JSON序列化循环。

你正在发送一个PostDTO列表,但是将JsonBackReference应用于Comments,将JsonManagedReference应用于Posts

更新

注意,ObjectMapper类,JsonManagedReferenceJsonBackReference可能来自2个包:

  • com.fasterxml.jackson.databind.ObjectMapper
  • com.fasterxml.jackson.annotation.JsonManagedReference
  • com.fasterxml.jackson.annotation.JsonBackReference

或者:

  • org.codehaus.jackson.map.ObjectMapper
  • org.codehaus.jackson.annotate.JsonManagedReference
  • org.codehaus.jackson.annotate.JsonBackReference

如果它们之间不一致,不匹配的注释将被忽略,您在序列化期间仍将遇到无限循环。

英文:

You are breaking the json serialization cycle on the wrong class.

You are sending a list of PostDTO, but applied JsonBackReference to Comments and JsonManagedReference to Posts

Update

Note that ObjectMapper class, JsonManagedReference and JsonBackReference may from 2 packages

  • com.fasterxml.jackson.databind.ObjectMapper
  • com.fasterxml.jackson.annotation.JsonManagedReference
  • com.fasterxml.jackson.annotation.JsonBackReference

or:

  • org.codehaus.jackson.map.ObjectMapper
  • org.codehaus.jackson.annotate.JsonManagedReference
  • org.codehaus.jackson.annotate.JsonBackReference

If you are not consistent between all of them, the mis-matched annotation will be ignored and you will still experience infinite loop during serialization.

答案3

得分: 0

使用 JsonIgnoreProperties 与管理和反向引用

@Data
@Entity
@Table(name = "comments")
@EntityListeners(AuditingEntityListener.class)
public class Comments {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "comment_id")
    private Long comment_id;

    @OneToOne
    @JoinColumn(name = "user_id")
    private Users user;

    @Column(name = "description")
    private String description;

    @Column(name = "images")
    private String images;

    @ManyToOne
    @JoinColumn(name = "post_id", nullable = false)
    @JsonIgnoreProperties(value = { "comments", "hibernateLazyInitializer", "handler" }, allowSetters = true)
    @JsonBackReference
    private Posts post;

    @Column(name = "last_updated")
    @LastModifiedDate
    private Date lastUpdated;

}

你的 Post 类应该是

@Data
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
public class Posts {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "post_id")
    private Long post_id;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private Users user;

    @Column(name = "description")
    private String description;

    @Column(name = "images")
    private String images;

    @Column(name = "tags")
    private String tags;

    @OneToMany(
        fetch = FetchType.LAZY,
        mappedBy = "post",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    @JsonIgnoreProperties(value = { "post", "hibernateLazyInitializer", "handler" }, allowSetters = true)
    @JsonManagedReference
    private List<Comments> comments;

    @LastModifiedDate
    @Column(name = "last_updated")
    private Date lastUpdated;

    public void addComments(Comments comment) {
        this.comments.add(comment);
    }
}

此外我建议使用 Getter 和 Setter 注释而不是 @Data因为 ToString() 方法会导致递归
英文:

Use JsonIgnoreProperties along with Manage and backreference .

 @Data
@Entity
@Table(name = &quot;comments&quot;)
@EntityListeners(AuditingEntityListener.class)
public class Comments {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name=&quot;comment_id&quot;)
private Long comment_id;
@OneToOne
@JoinColumn(name = &quot;user_id&quot;)
private Users user;
@Column(name = &quot;description&quot;)
private String description;
@Column(name=&quot;images&quot;)
private String images;
@ManyToOne
@JoinColumn(name =&quot;post_id&quot; , nullable = false)
@JsonIgnoreProperties(value = { &quot;comments&quot; ,&quot;hibernateLazyInitializer&quot;, &quot;handler&quot; }, allowSetters = true)
@JsonBackReference
private Posts post;
@Column(name=&quot;last_updated&quot;)
@LastModifiedDate
private Date lastUpdated;
}

And Your Post class should be

@Data
@Entity
@Table(name = &quot;posts&quot;)
@EntityListeners(AuditingEntityListener.class)
public class Posts {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = &quot;post_id&quot;)
private Long post_id;
@ManyToOne
@JoinColumn(name = &quot;user_id&quot;, nullable = false)
private Users user;
@Column(name = &quot;description&quot;)
private String description;
@Column(name=&quot;images&quot;)
private String images;
@Column(name=&quot;tags&quot;)
private String tags;
@OneToMany(
fetch = FetchType.LAZY,
mappedBy = &quot;post&quot;,
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JsonIgnoreProperties(value = { &quot;post&quot; ,&quot;hibernateLazyInitializer&quot;, &quot;handler&quot; }, allowSetters = true)
@JsonManagedReference
private List&lt;Comments&gt; comments;
@LastModifiedDate
@Column(name = &quot;last_updated&quot;)
private Date lastUpdated;
public void addComments(Comments comment) {
this.comments.add(comment);
}
}

Also I would suggest to Use Getter and Setter annotation instead of @Data .Because Tostring() method will cause recursion also .

huangapple
  • 本文由 发表于 2020年4月9日 13:35:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/61114583.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定