JPA - @PreRemove方法行为

Kub*_*tny 6 java hibernate jpa

我有2个具有多对多关系的实体.电影实体是此关系的所有者,因此当我想删除一个Actor实体时,我使用注释@PreRemove的方法删除Movie Cast中出现的任何Actor ID,以避免"外键违规异常".

电影课

@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()

}
Run Code Online (Sandbox Code Playgroud)

演员班

@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);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

要清楚,从我的测试中,它可以工作 - 电影对象在数据库中正确更新.但是,我无法理解在没有调用saveOrUpdate()或者持久化/合并这些对象时怎么可能.

JB *_*zet 13

这是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
}
Run Code Online (Sandbox Code Playgroud)

persist() 用于使新实体持久化,即使其由Hibernate管理.

merge() 用于获取分离的实体(即不是由Hibernate管理但已经具有ID和状态的实体)并将其状态复制到具有相同ID的附加实体.