spring - Spring boot Hibernate 多对多关系。传递给持久化的分离实体:
问题描述
我有 2 个具有多对多关系的实体 Product 和 ProductOptions。
@Entity
public class Product {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String description;
private String productCategory;
private String optionDescription;
private BigDecimal productBasePrice;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="product_productoption",joinColumns=@JoinColumn(name="Product_id"), inverseJoinColumns=@JoinColumn(name="ProductOption_id"))
private Set<ProductOption>productOptions=new HashSet<>();
}
和
@Entity
public class ProductOption {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String productOptionDescription;
private BigDecimal optionPrice;
private BigDecimal optionPriceForSmall;
private BigDecimal optionPriceForNormal;
private BigDecimal optionPriceForFamily;
private BigDecimal optionPriceForParty;
@ManyToMany(mappedBy = "productOptions")
private Set<Product>product=new HashSet<>();
}
数据初始化
private void initProducts() {
ProductOption productOpton1=new ProductOption("mit Cocktailsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton2=new ProductOption("mit Joghurtsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton3=new ProductOption("ohne Sauce", new BigDecimal(0), null, null, null, null);
Product product37= new Product("Falafel", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.00));
product37.getProductOptions().add(productOpton1);
product37.getProductOptions().add(productOpton2);
product37.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product37);
productOpton2.getProduct().add(product37);
productOpton3.getProduct().add(product37);
Product product38= new Product("Falafel Yufka Dürüm", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.50));
product38.getProductOptions().add(productOpton1);
product38.getProductOptions().add(productOpton2);
product38.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product38);
productOpton2.getProduct().add(product38);
productOpton3.getProduct().add(product38);
this.productRepository.save(product37);
this.productRepository.save(product38);
}
它给了我以下异常
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: xx.xy.zz ProductOption
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:127) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:726) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:694) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:298) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
但如果我不坚持产品38
this.productRepository.save(product38);
那么我没有任何问题。似乎我不能多次保留同一个实例?因为 productOption 1-3 已经与 product37 一起保留?
product38.getProductOptions().add(productOpton1);
product38.getProductOptions().add(productOpton2);
product38.getProductOptions().add(productOpton3);
尽管内容相同,但我是否每次都必须创建新实例。这里有什么解决方法吗?
请指教。谢谢。
**更新**忘记提及 Equals 在两个实体中都实现了。
@覆盖
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ProductOption other = (ProductOption) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (optionPrice == null) {
if (other.optionPrice != null)
return false;
} else if (!optionPrice.equals(other.optionPrice))
return false;
if (optionPriceForFamily == null) {
if (other.optionPriceForFamily != null)
return false;
} else if (!optionPriceForFamily.equals(other.optionPriceForFamily))
return false;
if (optionPriceForNormal == null) {
if (other.optionPriceForNormal != null)
return false;
} else if (!optionPriceForNormal.equals(other.optionPriceForNormal))
return false;
if (optionPriceForParty == null) {
if (other.optionPriceForParty != null)
return false;
} else if (!optionPriceForParty.equals(other.optionPriceForParty))
return false;
if (optionPriceForSmall == null) {
if (other.optionPriceForSmall != null)
return false;
} else if (!optionPriceForSmall.equals(other.optionPriceForSmall))
return false;
if (productOptionDescription == null) {
if (other.productOptionDescription != null)
return false;
} else if (!productOptionDescription.equals(other.productOptionDescription))
return false;
return true;
}
首先保存 ProductOptions 并重用它们也无济于事。
private void initProducts() {
ProductOption productOpton1=new ProductOption("mit Cocktailsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton2=new ProductOption("mit Joghurtsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton3=new ProductOption("ohne Sauce", new BigDecimal(0), null, null, null, null);
Product product37= new Product("Falafel", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.00));
product37.getProductOptions().add(productOpton1);
product37.getProductOptions().add(productOpton2);
product37.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product37);
productOpton2.getProduct().add(product37);
productOpton3.getProduct().add(product37);
Product product38= new Product("Falafel Yufka Dürüm", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.50));
product38.getProductOptions().add(productOpton1);
product38.getProductOptions().add(productOpton2);
product38.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product38);
productOpton2.getProduct().add(product38);
productOpton3.getProduct().add(product38);
this.productOptionRepository.save(productOpton1);
this.productOptionRepository.save(productOpton2);
this.productOptionRepository.save(productOpton3);
this.productRepository.save(product37);
this.productRepository.save(product38);
}
解决方案
如果要在一种方法中保存多个不同的数据,则需要在方法 initProducts 处使用 @Transactional。问题似乎是,在您想要保存 product38 的那一刻,ProductOptions 尚未保存在 DB 中。使用@Transactional spring 创建一个事务并执行所有操作。