【问题标题】:JPA2.0: Delete Entity in OneToMany RelationShipJPA2.0:删除 OneToMany RelationShip 中的实体
【发布时间】:2011-08-04 06:16:58
【问题描述】:

如何删除 OneToMany 关系中的实体。

@Entity
@NamedQueries({
   @NamedQuery(name="User.findByUserNamePassword",
     query="select c from User c where c.userName = :userName AND c.password = :password")
})
@Table(name="\"USER\"")
public class User implements Serializable {
    @OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemove=true)
    private List<Profession> professions;

    public List<Profession> getProfessions() {
       return professions;
    }

    public void setProfessions(List<Profession> professions) {
       this.professions = professions;
    }

    public void addProfession(Profession profession){
       if(this.professions == null){
          this.professions = new ArrayList<Profession>();
       }
       this.professions.add(profession);
       profession.setUser(this);
    }

    public void removeProfession(Profession profession){
       if(this.professions != null){
          professions.remove(profession);
          profession.setUser(null);
       }
    }
}

内部职业实体

@Entity
public class Profession implements Serializable {
    @ManyToOne
    @JoinColumn(name="UserId", nullable=false)
    private User user;

    public User getUser() {
       return user;
    }

    public void setUser(User user) {
       this.user = user;
    }

然后在我的 EJB 里面我有这个

@Stateless
@LocalBean
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ScholarEJB{

    /**
     * Add a profession to a target user
     * @param user
     * @param profession
     */
    public void addProfession(User user, Profession profession){
        //Put the user in a managed state. It is important to do this before
        //adding a new profession onto user
        user = find(User.class, user.getId());
        user.addProfession(profession);
        this.create(user);   //This is persist action
    }

    public void removeProfession(User user, Profession profession){
        //Put the user in a managed state. It is important to do this before
        //adding a new profession onto user
        user = find(User.class, user.getId());
        user.remove(user);
        this.update(user);  //merge action
        //this.create(user) //also try this as well, but it does not work
    }
}

现在addProfession 工作得很好,但removeProfession 不起作用。不知道为什么?请帮忙。我需要驱逐缓存吗?

【问题讨论】:

  • 在你的一对多关系中,正确的注解是 orphanRemoval=true,而不是 orphanRemove=true

标签: jpa ejb jpa-2.0 one-to-many


【解决方案1】:

如果职业只是这种关系的一部分,那么您可以保证,当从用户集中删除一个职业时,通过在关系的 OneToMany 一侧打开 orphanRemoval,它也会从数据库中删除。

@OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Profession> professions;

这就是 JPA 2.0 规范的规定

JPA 2.0 规范声明

指定为的关联 OneToOne 或 OneToMany 支持使用 orphanRemoval 选项。这 以下行为适用于 orphanRemoval 生效:

如果一个实体是 关系被删除 关系(通过设置 与 null 的关系或删除 关系中的实体 集合),删除操作将 被应用到实体 孤儿。删除操作是 在冲洗时应用 手术。孤儿移除 功能适用于实体 由他们私人“拥有”的 母实体。便携式应用程序 否则不得依赖于 删除的具体顺序,并且必须 不重新分配已被 成为另一段关系的孤儿或 否则尝试坚持下去。如果 被孤立的实体是 分离的、新的或移除的实体, orphanRemoval 的语义不 申请。

如果删除操作应用于 托管源实体,删除 操作将级联到 关系目标按照 第 3.2.3 节的规则,(因此 没有必要指定 级联=删除 关系)[20]。

【讨论】:

  • 遗憾的是我尝试了它,但仍然无法正常工作。但我知道什么工作。我必须清除二级缓存才能正常工作。 profession = em.merge(profession); em.remove(profession); em.getEntityManagerFactory().getCache().evictAll();,这项工作,但我不确定这是否是最好的方法
  • 您可以发布您的更新方法吗?它说它进行了合并,这在您当前的代码中并不清楚或不明显。
【解决方案2】:

我对正在发生的事情的猜测是,您的 User 与 Profession 具有 OneToMany 关系,而您的 user 对象具有该专业。当您删除职业时,用户仍然拥有参考。因为映射是级联持久化的,所以会重新持久化Profession。

您需要确保在删除之前从用户的职业中删除该职业。

如果您使用的是 EclipseLink,则有一个属性可能也会有所帮助,但修复您的代码以正确维护您的模型是最好的解决方案。您也可以移除级联持久化。

"eclipselink.persistence-context.persist-on-commit"="false"

或者, "eclipselink.persistence-context.commit-without-persist-rules"="true"

【讨论】:

    【解决方案3】:

    您可以尝试清除职业中的用户字段:

    public void removeProfession(Profession profession){
           if(this.professions != null){
              professions.remove(profession);
              profession.setUser(null);  // disassociate profession from user
           }
        }
    

    为了安全起见,我还会检查传入的职业的当前用户是否等于this,以防有人传入属于另一个用户的职业。

    【讨论】:

    • 也试试,还是不行。我在删除之后打印出职业列表,在我坚持/合并之前,列表恢复正确。但是当我坚持/合并时,这并没有反映在我的数据库中
    【解决方案4】:

    这是我最初问题的解决方案,但是,我不知道这是否是最好的

    我的 EJB bean

    @PersistenceContext(unitName="Bridgeye2-ejbPU")
    private EntityManager em;
    
    public <T> T create(T t) {
        em.persist(t);
        return t;
    }
    
    public <T> T find(Class<T> type, Object id) {
        return em.find(type, id);
    }
    
    public <T> void delete(T t) {
        t = em.merge(t);
        em.remove(t);
    }
    
    public <T> void removeAndClearCaches(T t){
        this.delete(t);
        clearCaches();
    }
    
    public <T> T update(T t) {
        return em.merge(t);    
    

    现在在我的托管 Bean 中,我这样做了

    /**
     * Add a new profession 
     */
    public void addNewProfession(){
        Profession profession = new Profession();        
        newProfessions.add(profession);        
    }
    
    /**
     * Remove the profession
     * @param profession
     */
    public void removeProfession(Profession profession){
        //This will remove the `profession` of the list
        //at the presentation layer
        this.myProfessions.remove(profession);  
        //This will remove the `profession` of the list
        //at the persistence layer
        scholarEJB.removeAndClearCaches(profession);
    }
    

    【讨论】:

      【解决方案5】:

      我刚刚在 OneToMany 关系中添加了orphanRemoval = true,我解决了它。

      班级SolicitudRetorno:

      @OneToMany(mappedBy = "solicitud", cascade = CascadeType.ALL, orphanRemoval = true)
      @LazyCollection(LazyCollectionOption.FALSE)
      @NotAudited
      private List<RetornoMenor> hijosRetorno;
      

      班级RetornoMenor:

      @OneToMany(mappedBy = "solicitud", cascade = CascadeType.ALL, orphanRemoval = true)
      @LazyCollection(LazyCollectionOption.FALSE)
      @NotAudited
      private List<RetornoMenor> hijosRetorno;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-09
        • 1970-01-01
        • 2019-07-09
        • 1970-01-01
        • 1970-01-01
        • 2020-06-25
        • 1970-01-01
        相关资源
        最近更新 更多