如何在@ManyToOne JPA 中停止重复对象?
Posted
技术标签:
【中文标题】如何在@ManyToOne JPA 中停止重复对象?【英文标题】:How to stop repeating objects in @ManyToOne JPA? 【发布时间】:2018-01-15 00:55:26 【问题描述】:我的父类:
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> child;
public List<Child> getChild()
return child;
public void setChild(List<Child> child)
this.child = child;
我的孩子班:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "REF_ID")
private Parent parent;
public Parent getParent()
return parent;
public void setParent(Parent parent)
this.parent = parent;
错误:
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:626) ~[tomcat-embed-core-8.5.15.jar:8.5.15]
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:211) ~[tomcat-embed-core-8.5.15.jar:8.5.15]
at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:109) ~[tomcat-embed-core-8.5.15.jar:8.5.15]
at org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView.render(ErrorMvcAutoConfiguration.java:227) ~[spring-boot-autoconfigure-1.5.4.RELEASE.jar:1.5.4.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1286) ~[spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1041) ~[spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:984) ~[spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
... 38 common frames omitted
在浏览器中:
它看起来像来自父实体的@OneToMany 调用子对象很好。但是子实体中的@ManyToOne 通过再次调用父对象并重复它来做同样的事情。如何避免这个问题?
【问题讨论】:
您没有在 JPA 中重复任何内容。您在生成 JSON 时重复,这与 JPA API 无关。 是的,尼尔知道了。谢谢。 【参考方案1】:在您的子类中忽略使用@JsonIgnore 序列化/反序列化您的父类
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "REF_ID")
private Parent parent;
public Parent getParent()
return parent;
public void setParent(Parent parent)
this.parent = parent;
【讨论】:
这是我认为最好的解决方案。 有人知道上层解决方案和这个解决方案的区别吗? brian 的解决方案和 Amer 的解决方案是哪个?【参考方案2】:我会像这样使用@JsonManagedReference 和@JsonBackReference:
家长
@JsonBackReference
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> child;
孩子
@JsonManagedReference
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "REF_ID")
private Parent parent;
发生了什么?
这与 JPA 无关。您的 @Entity 模型提供了访问字段的方法。要在 API 中表示它们,您需要对它们进行序列化。序列化程序不知道该级别的实体(它会知道持久层。这将违反SRP)。因此,您必须像在实体模型上使用 @ManyToOne、@OneToMany 一样提供序列化程序提示。序列化程序遍历类的 get 方法,并调用它们。如果没有提示,您最终会得到一个循环引用,因为您调用了父级,然后获取了子级。一旦序列化孩子,你再次调用父母。
来自参考文献
@JsonManagedReference:注解用来表示被注解的属性是字段之间双向链接的一部分;并且它的角色是“父”(或“转发”)链接。
@JsonBackReference:用于表示关联属性是字段之间双向链接的一部分的注解;并且它的作用是“子”(或“后”)链接
【讨论】:
没问题。如果这有效,请记住将其标记为答案。 有疑问我们不能在 JPA 本身中执行此操作吗? 与JPA无关。 JPA 代表资源。序列化时,默认情况下会调用方法。您必须在序列化程序上“提示”,以便它具有有关如何序列化的其他详细信息。 我添加了解释以便更好地解释。希望对您有所帮助。【参考方案3】:从可接受的答案和其他人提出的注释基本上是告诉spring boot跳过阅读它们。是的,它能够解决循环问题,但并不能完全解决返回预期 json 输出的问题。
相反,我对这些实现做了一些改动,它对我有用!
交换参考注释
父实体 -> @JsonManagedReference 子实体 -> @JsonBackReference代码片段示例:
Parent.java(类)
@JsonManagedReference
@OneToMany(fetch = FetchType.LAZY, mappedBy = "parent", cascade = CascadeType.ALL) //"parent" -> is the name defined by child class
private List<Child> childs;
Child.java(类)
@JsonBackReference
@ManyToOne
@JoinColumn(name = "parent_id") //parent_id is the foreign key for child
private Parent parent; //object name defined from Parent class
上面的交换对我有用。
【讨论】:
以上是关于如何在@ManyToOne JPA 中停止重复对象?的主要内容,如果未能解决你的问题,请参考以下文章
JPA。 FetchType.Lazy 引起了奇怪的行为@ManyToOne