2016-09-09 72 views
0

我随机得到以下例外:org.eclipse.persistence.exceptions.ValidationException Exception Description: The attribute [id] of class [domain.Person] is mapped to a primary key column in the database. Updates are not allowed.如何避免在与jpa使用manytomany关系时出现ValidationException?

执行“deleteAllPersons()”时主要抛出异常。当两个实体之间存在必须删除的链接时,就会出现该错误,并且似乎发生在第二个被删除的人身上。

值得注意的是,错误通常不会在调试模式下出现,也不会在测试套件自行运行时出现。这导致我认为问题可能与时间有关,或者原因是在某些情况下在导致任何问题之前自动解决的不一致。

public void deleteAllPersons(){ 
     for(Person person: getAllPersons()){ 
      long id = person.getId(); 
      deletePerson(id); 
     } 

与deletePerson的(ID)方法是

public void deletePerson(long id) { 
     Person person = getPerson(id);    
      List<OrderBill> ordersToBeUnlinked = new ArrayList<>(); 
      ordersToBeUnlinked.addAll(person.getOrders()); 

      for (OrderBill order : ordersToBeUnlinked) {     
       person.removeOrder(order); 
       System.out.println(order + "deleted"); 
      }   
     try{  
      manager.getTransaction().begin(); 
      manager.merge(person); 
     } catch (Exception e1){ 
      throw new DbException("Error merging person" + person + "\n" + e1.getMessage(), e1); 
     } 
     try { 
      manager.remove(person); 
      manager.flush();    
      manager.getTransaction().commit(); 
     } catch (Exception e){ 
      manager.getTransaction().rollback(); 
      throw new DbException("error deleting " + person + "\n" + e.getMessage(), e); 
     }  
    } 

合并去罚款,但在删除会抛出异常。 在异常消息,我可以看到人在它没有更多订单的名单

在情况下,我在个人或OrderBill类犯了一个错误, 下面是这两个类的最重要的部分:

@Entity(name="Person") 
public class Person { 
    @Id 
    @Column(name="PERSON_ID") 
    @GeneratedValue 
    private long id; 

    @ManyToMany(mappedBy="authors", fetch=FetchType.LAZY, cascade={CascadeType.MERGE}) 
    private Set<OrderBill> orders; 
@Column(name="name") 
    private String name = "undefined"; 
    public Person(String name){ 
     setName(name); 
     payments = new HashSet<Payment>(); 
     orders = new HashSet<OrderBill>(); 
    } 
    public void removeOrder(OrderBill order){ 
     orders.remove(order); 
     if(order.getAuthors().contains(this)){ 
      order.removeAuthor(this); 
     } 
    } 

OrderBill:

@Entity(name="OrderBill") 
@NamedQueries({ 
    @NamedQuery(name="Order.getAll", query="select o from OrderBill o"), 
    @NamedQuery(name="Order.findOrders", query="select o from OrderBill o join o.orderWeek as w where (w.weekNr = :w and w.yearNr = :y)") 
}) 
public class OrderBill implements Transaction{ 
    @Id 
    @Basic(optional = false)        
    @NotNull 
    @Column(name="ORDER_ID") 
    @GeneratedValue 
    private long id; 

    @ManyToMany 
    @JoinTable(
      name="ORDER_PERSON", 
      [email protected](name="ORDER_ID"), 
      [email protected](name="PERSON_ID") 
    ) 
    private Set<Person> authors; 

     public OrderBill(double totalCost, int weekNr, int yearNr){ 
      setOrderWeek(new OrderWeek(weekNr, yearNr)); 
      setTotalCost(totalCost); 
      authors = new HashSet<>(); 
     } 

    public void removeAuthor(Person author){ 
     authors.remove(author); 
     if(author.getOrders().contains(this)) 
      author.removeOrder(this); 
    } 
+1

这是一种双向关系,因此当您去删除一个人时,您还需要从任何OrderBill实例中删除对该人员实例的所有引用。其中之一是引用它,导致下一个事务的持久性单元出现错误。 – Chris

回答

0

在情况下,它可以帮助别人,我会写我有什么发现如下:

克里斯的评论结果是正确的,但我花了很长时间才发现我试图删除所有引用时犯了一个错误。

我不知道这是不是唯一的问题,但我发现一个主要的逻辑缺陷:

  1. 当我要删除我第一次删除订单列表,并比其所有引用的人合并人员以更新数据库。

但订单列表被标记为“的mappedBy”,所以其变化将不在数据库中反映

  • 我已通过“订单”列表中更新每个订单人,所以我预计级联合并处理它
  • 但通过更新人,与订单列表被清空。正因为如此,当人被合并到更新的订单没有引用左(所以级联合并并不影响他们)

    我在deletePerson的

    for循环中添加合并(顺序)固定的问题
    for (OrderBill order : ordersToBeUnlinked) {     
        person.removeOrder(order); 
        manager.merge(order); 
        } 
    

    注意:当然,由于合并,我必须把这个for循环放在一个事务中。

    相关问题