jpa:更新新父实体的关系

Posted

技术标签:

【中文标题】jpa:更新新父实体的关系【英文标题】:jpa: update relationship for a new parent-entity 【发布时间】: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 的关系找到了一个新对象

【问题讨论】:

【参考方案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();

【讨论】:

这样它只是作为例外工作。很高兴知道,以后会留意你的建议。非常感谢!

以上是关于jpa:更新新父实体的关系的主要内容,如果未能解决你的问题,请参考以下文章

JPA:在父子关系中->父未更新

Spring Jpa Data Repository使用LinkedEntity for ManyToMany关系保存(更新)

更新孩子时如何更新jpa中双向关系所有者的fk

更新多对多关系中的实体

JPA:仅更新映射表

Spring JPA:使用更新的子实体更新实体