jpa: обновить отношения для нового родительского объекта

у меня есть две сущности Price‹-1----1->PriceDetail, сопоставленные как OneToOne.

как я могу обрабатывать различные сценарии для этого отношения. поэтому у меня есть случаи, когда мне всегда нужна новая цена и новая цена, но я также смогу создать только новую цену и обновить цену (с данными из предыдущей цены). мое текущее решение состоит в том, чтобы удалить объект pricedetail, как это можно сделать, обновив объект pricedetail?

@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-Annotation в Price-Entity JPA пытается вставить новый PriceDetail-Entity.

подход 1:

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

-> Ошибка: вставка в pricedetail нарушает ограничение уникальности: ключ уже существует

подход 2:

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

тогда подход 1 работает, но создание полностью новой цены приводит к следующему: Во время синхронизации был найден новый объект через связь, которая не была помечена как каскадная PERSIST


person Steve    schedule 11.08.2016    source источник


Ответы (1)


подход 2 не подходит в вашем случае, это правильное сопоставление для двунаправленной взаимно-однозначной ассоциации:

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

Теперь проблема в том, что: цена является новой сущностью, тогда entityManager вызовет операцию persit для price.getpriceDetail(), потому что каскадное сохранение запускается автоматически (не каскадное слияние), чтобы избежать этого странного поведения, вы можете сделать следующее.

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();
person SEY_91    schedule 11.08.2016
comment
таким образом, он просто работает как исключение. приятно знать, буду следить за вашим предложением в будущем. огромное спасибо! - person Steve; 11.08.2016