我正在使用 Spring Boot 编写 OneToMany 关系,一个属性可以有多个 propertySale。
这是我的属性类:
@Data
@Getter
@Entity
@Table(name = "Property")
public class Property {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy="property", cascade = CascadeType.ALL, targetEntity = PropertySale.class)
@JsonManagedReference
private Set<PropertySale> propertySales;
...
这是我的 propertySale 类:
@Data
@Getter
@Entity
@Table(name = "PropertySale")
public class PropertySale {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "property_id", referencedColumnName = "id")
@JsonBackReference
private Property property;
...
我像这样保存 propertySale:
@Override
public ResponseEntity<PropertySale> savePropertySale(PropertySale propertySale) {
Optional<Property> existPropertyOpt = this.propertyRepository.findById(propertySale.getProperty().getId());
if(existPropertyOpt.isPresent()){
Example<PropertySale> propertySaleExample = Example.of(propertySale);
Optional<PropertySale> existPropSale = this.propertySaleRepository.findOne(propertySaleExample);
if(existPropSale.isPresent()){
throw new PropertySaleAlreadyExistException();
}else{
Property existProperty = existPropertyOpt.get();
propertySale.setProperty(existProperty);
existProperty.addPropertySale(propertySale);
this.propertyRepository.save(existProperty);
return new ResponseEntity<>(propertySale, HttpStatus.CREATED);
}
}else{
throw new PropertyNotFoundException(propertySale.getProperty().getId());
}
}
我明白
Caused by: java.lang.StackOverflowError
at java.util.AbstractSet.hashCode(AbstractSet.java:122)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:459)
at com.mikason.PropView.dataaccess.estateEntity.Property.hashCode(Property.java:12)
at com.mikason.PropView.dataaccess.commercialEntity.PropertySale.hashCode(PropertySale.java:10)
at java.util.AbstractSet.hashCode(AbstractSet.java:126)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:459)
at com.mikason.PropView.dataaccess.estateEntity.Property.hashCode(Property.java:12)
at com.mikason.PropView.dataaccess.commercialEntity.PropertySale.hashCode(PropertySale.java:10)
at java.util.AbstractSet.hashCode(AbstractSet.java:126)
...
当我尝试保存特性销售时,有人可以告诉我哪里做错了吗?非常感谢。
最佳答案
简短回答
在PropertySale
的字段property
中添加@EqualsAndHashCode.Exclude
注释。
长答案
发生这种情况是因为:
default implementation of
Set
used by Hibernate isHashSet
,它基于其元素的哈希码来存储它们,并且...由于您使用的是 Lombok 的
@Data
注释,因此哈希码(以及 equals 和 toString)实现会考虑所有类字段。这意味着Property.hashCode()
调用PropertySale.hashCode()
,反之亦然,导致每当调用其中任何一个时都会出现堆栈溢出错误(这如果您使用这两个类中的任何一个调用.equals()
或.toString()
,也会发生这种情况。
为了解决此问题,您可以使用一些选项:
- 将
Property
类中的@Data
替换为@Getter
和@Setter
。由于它不用作Set
内的元素,因此它可能 doesn't need to overridehashCode
/equals
,与PropertySale
不同。 - 在字段
PropertySale.property
上添加@EqualsAndHashCode.Exclude
(和@ToString.Exclude
),因此PropertySale.hashCode
不会调用Property.hashCode
。 - 为
PropertySale
编写您自己的hashCode
/equals
实现(在这种情况下,Lombok 不会生成它们),而无需调用Property .hashCode
(例如,您仍然可以使用Property.id
)。
奖金
正如我提到的,toString
可能会出现同样的问题,但修正方法与 equals
/hashCode
几乎相同:ToString.Exclude
/避免@Data
/自定义实现...
您还可以编写单元测试,以确保在运行应用程序时这些方法都不会抛出 StackOverflowError
。
关于java - 保存 OneToMany 关系时总是获得无限递归(已使用 @JsonBackReference 和 @JsonManagedReference),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57932048/