我正在使用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;
...
我这样保存物业出售:
@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)
...
当我尝试保存财产出售时,有人可以告诉我我做错了什么吗?非常感谢你。
最佳答案
简短答案
将@EqualsAndHashCode.Exclude
批注添加到property
的字段PropertySale
。
长答案
发生这种情况是因为:
default implementation of Set
used by Hibernate is HashSet
,基于其元素的哈希码存储它们,并...
由于您正在使用Lombok的@Data
批注,因此哈希码(以及equals和toString)实现将所有类字段都考虑在内。这意味着Property.hashCode()
调用PropertySale.hashCode()
,反之亦然,从而导致每次调用它们中的任何一个时都会出现堆栈溢出错误(如果您使用以下任何一个调用.equals()
或.toString()
,也会发生堆栈溢出错误这两个类)。
为了解决这个问题,您可以使用一些选项:
在类@Data
上将@Getter
替换为@Setter
和Property
。由于它不用作Set
中的元素,因此可能不同于hashCode
而是doesn't need to override equals
/PropertySale
。
在字段@EqualsAndHashCode.Exclude
上添加@ToString.Exclude
(和PropertySale.property
),因此PropertySale.hashCode
不会调用Property.hashCode
。
在不调用hashCode
的情况下为equals
编写自己的PropertySale
/ Property.hashCode
实现(在这种情况下Lombok不会生成它们)(例如,您仍然可以使用Property.id
)。
奖金
正如我提到的,toString
可能会出现相同的问题,但更正与equals
/ hashCode
相同:ToString.Exclude
/避免@Data
/自定义实现...
您还可以编写单元测试,以确保在运行应用程序时这些方法均不会抛出StackOverflowError
。
关于java - 保存OneToMany关系时始终获得无限递归(已使用@JsonBackReference和@JsonManagedReference),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57932048/