2013-11-03 363 views
3

我有2个具有多对多关系的实体。 Movie Entity是此关系的所有者,因此,当我想要删除Actor实体时,我使用注释@PreRemove的方法删除Movie Movie中的任何Actor ID以避免出现“外键违例异常”。JPA - @PreRemove方法行为

电影类

@Entity 
public class Movie extends AbstractBusinessObject{ 

    @ManyToMany 
    private Map<String, Actor> cast; 

    // setters and getters 

    public void removeCastMember(Actor actor){ 

     for (Entry<String, Actor> e : cast.entrySet()) { 
      if(e.getValue().id.equals(actor.id)){ 
       cast.remove(e.getKey()); 
      } 
     } 

    } // removeCastMember() 

} 

演员类

@Entity 
public class Actor extends AbstractBusinessObject{ 

    @ManyToMany(mappedBy = "cast") 
    private Set<Movie> movies; 

    // setters and getters 

    @PreRemove 
    private void removeActorFromMovies() { 
     for (Movie m : movies) { 
      m.removeCastMember(this); 
     } 
    } 

} 

需要明确的是,从我的测试中,它的作品 - 电影对象正确地在数据库中更新。然而,我不明白在没有调用saveOrUpdate()或持久化/合并这些对象的时候它怎么可能。

回答

8

这是JPA/Hibernate的一个基本特性。对连接实体所做的所有更改都会自动保持不变:Hibernate管理它们,以便将其当前状态与其初始状态进行比较,并自动使所有更改持久化。

这非常有用,因为您不必跟踪修改大量实体的复杂业务方法中已修改的所有实体。而且它也很有效,因为Hibernate不会执行不必​​要的SQL:如果实体在事务期间没有更改,则不会为此实体执行SQL更新查询。如果你修改实体,然后抛出异常回滚事务,Hibernate将跳过更新。

因此,典型的JPA代码是这样的:

void transfer(Long fromAccountId, Long toAccountId, BigDecimal amount) { 
    Account from = em.find(Account.class, fromAccountId); // from is managed by JPA 
    Account to = em.find(Account.class, ftoAccountId); // to is managed by JPA 
    from.remove(amount); 
    to.add(amount); 

    // now the transaction ends, Hibernate sees that the state of from and to 
    // has changed, and it saves the entities automatically before the commit 
} 

persist()是用来制造一个新的实体持久性,即,使其由Hibernate管理。

merge()用于接受分离的实体(即,不是由Hibernate管理但已经具有ID和状态的实体)并且将其状态复制到具有相同ID的附属实体。

+0

谢谢你这么详细的回答。我真的忘记了重要的部分:'合并是用来分离实体'。 –