jpa:更新新父实体的关系

jpa: update relationship for a new parent-entity

我有两个实体 Price<-1----1->PriceDetail 映射为 OneToOne.

我该如何处理这种关系的不同场景。所以我有这样的情况,我总是想要一个新的价格和一个新的价格细节, 但我也只能创建新价格并更新价格详情(使用来自先前价格实体的数据)。 我目前的解决方案是删除 pricedetail-entity,如何通过更新 pricedetail-entity 来完成?

@Entity
class Price {

  @OneToOne(cascade=CascadeType.ALL,mappedBy = "price")
  private PriceDetail priceDetail;
}

@Entity
class PriceDetail {

  @OneToOne
  private Price price;
}

保存方法:

EntityManage em = getEntityManager();

for (Price price : getAllPrices()){ 

  Price oldPrice =  Price.getById(price.getId());               

  if (!oldPrice.equals(price)){ //if we have price-changes

     if (PriceCatalog.entryExists(oldPrice)){ //if the current-price is in a catalog

      //current solution: remove entry from PriceDetail, but i want to update PriceDetail-Entity, pointing 
      //to the newly created price
      em.remove(oldPrice.getPriceDetail());
      em.commitTransaction();

      oldPrice.setActive(false);  //referenced price in PriceCatalog is now inactive                

      //sets id null, so that a new price-entity is created
      price.setId(null);            
      price.setActive(true);                        
      em.persist(price);   //also inserts a new price-detail

     }else {
      em.merge(price);
     }
   }                        
 }
 em.commitTransaction();

由于 CascadeType.ALL-Price-Entity 中的注释,JPA 尝试插入一个新的 PriceDetail-Entity。

方法一:

price.getPriceDetail().setId(oldPrice.getPriceDetail().getId());

-> 错误:插入 pricedetail 违反唯一约束:密钥已存在

方法二:

  //ommit cascade
  @OneToOne(mappedBy = "price")
  protected PriceDetail priceDetail;

那么方法 1 可行,但创建一个全新的价格会导致: 在同步过程中,通过未标记为级联 PERSIST 的关系找到了一个新对象

方法 2 不适用于您的情况,这是执行双向一对一关联的正确映射:

//you must do this to handle the bidirectional association
  @OneToOne(mappedBy = "price")
  protected PriceDetail priceDetail;

现在的问题是:price 是一个新实体,然后 entityManager 将在 price.getpriceDetail() 上调用 persit 操作,因为级联持久化是自动触发的(不是级联合并)以避免这种奇怪的行为,您可以这样做以下。

EntityManage em = getEntityManager();

for (Price price : getAllPrices()){ 

  Price oldPrice =  Price.getById(price.getId());               

  if (!oldPrice.equals(price)){ //if we have price-changes

     if (PriceCatalog.entryExists(oldPrice)){ //if the current-price is in a catalog

      //current solution: remove entry from PriceDetail, but i want to update PriceDetail-Entity, pointing 
      //to the newly created price
      //em.remove(oldPrice.getPriceDetail());
      //em.commitTransaction();

      oldPrice.setActive(false);  //referenced price in PriceCatalog is now inactive                

      PriceDetail priceDetailold = price.getPriceDetail();
      price.setPriceDetail(null);
      priceDetailold.setPrice(null);
      //sets id null, so that a new price-entity is created
      price.setId(null);            
      price.setActive(true);  

      em.persist(price);   //inserts a new price
      price.setPriceDetail(priceDetailold);
      em.merge(price);// attach the pricedetail to the price
  }else {
      em.merge(price);
  }
 }                      
}
em.commitTransaction();