【问题标题】:jpa: update relationship for a new parent-entityjpa:更新新父实体的关系
【发布时间】:2016-08-11 11:49:06
【问题描述】:

我有两个实体 PricePriceDetail 映射为 OneToOne

我如何处理这种关系的不同情况。所以我有一些情况,我总是想要一个新的价格和一个新的价格细节, 但我也只能创建一个新价格并更新 pricedetail(使用来自先前价格实体的数据)。 我目前的解决方案是删除 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();

由于 Price-Entity 中的 CascadeType.ALL-Annotation,JPA 尝试插入新的 PriceDetail-Entity。

方法一:

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

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

方法二:

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

然后方法 1 可行,但创建一个全新的价格会导致: 在同步期间,通过未标记为 cascade PERSIST 的关系找到了一个新对象

【问题讨论】:

    标签: jpa eclipselink jpa-2.1


    【解决方案1】:

    在您的情况下,方法 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();
    

    【讨论】:

    • 这样它只是作为例外工作。很高兴知道,以后会留意你的建议。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2016-11-16
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 2019-08-16
    • 1970-01-01
    相关资源
    最近更新 更多