Spring boot休眠多对多关系。已传递到持久化的分离实体:
我有两个实体产品和产品选项与许多关系Spring boot休眠多对多关系。已传递到持久化的分离实体:,spring,hibernate,spring-boot,jpa,spring-data-jpa,Spring,Hibernate,Spring Boot,Jpa,Spring Data Jpa,我有两个实体产品和产品选项与许多关系 @Entity public class Product { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String description; private String productCategory; private String optionDescription; private Bi
@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<>();
}
它给了我以下的例外
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]
但是如果我不坚持下去
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创建事务并执行所有操作。您是否实现了equals()?@SimonMartinelli equals确实实现了。您应该先保存生产选项,然后将thme分配给product@SimonMartinelli这也无济于事。请查看我文章的最后一部分。我已经更新了代码。您必须在事务中运行initProducts
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;
}
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);
}