JPA2.0: удаление объекта в OneToMany RelationShip - PullRequest
6 голосов
/ 13 апреля 2011

Как удалить сущность в отношении 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);
       }
    }
}

Inside Profession Entity

@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 не работает. Не уверен почему? Помогите, пожалуйста. Нужно ли изгонять кеш?

Ответы [ 5 ]

9 голосов
/ 13 апреля 2011

Если профессии являются только частью этого отношения, то вы можете гарантировать, что когда профессия будет удалена из набора пользователя, она также будет удалена из базы данных, включив orphanRemoval на стороне OneToMany отношения.

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

Это то, что указано в спецификации JPA 2.0

В спецификации JPA 2.0 указано, что

Ассоциации, которые указаны как OneToOne или OneToMany поддерживают использование опция orphanRemoval. следующие поведения применяются, когда действует orphanRemoval:

Если объект, являющийся целью отношения удалены из отношения (установив отношение к нулю или удаление сущность из отношений сбор), операция удаления будет применяться к сущности осиротел. Операция удаления применяется во время сброса операция. СиротаУдалить функциональность предназначена для субъектов которые в частной собственности "принадлежат" их родительская сущность. Портативные приложения в противном случае не должно зависеть от конкретный порядок удаления, и должен не переназначать объект, который был осиротевший к другим отношениям или иначе попытайтесь упорствовать. Если Сирота является отдельный, новый или удаленный объект, семантика orphanRemoval не применяются.

Если операция удаления применяется к управляемый исходный объект, удаление операция будет каскадно цель отношений в соответствии с правила раздела 3.2.3, (и, следовательно, не нужно указывать каскад = УДАЛИТЬ для отношения) [20].

4 голосов
/ 13 апреля 2011

Я предполагаю, что происходит, когда ваш Пользователь имеет отношение OneToMany к Профессии, а ваш пользовательский объект имеет профессию. Когда вы удаляете Профессию, у пользователя остается ссылка. Поскольку отображение является каскадным сохранением, оно сохраняет Профессию.

Перед удалением необходимо убедиться, что вы удалили профессию из профессий пользователя.

Если вы используете EclipseLink, есть свойство, которое также может помочь, но исправление кода для правильного поддержания модели - лучшее решение. Вы также можете удалить этот каскад.

"eclipselink.persistence-context.persist-на-фиксации" = "ложь"

или, "Eclipselink.persistence-context.commit-без упорствовать-правила" = "истинный"

1 голос
/ 13 апреля 2011

Это решение моего первоначального вопроса, однако я не знаю, является ли это лучшим

Мой боб EJB

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

Теперь в моем управляемом бине я делаю это

/**
 * 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);
}
1 голос
/ 13 апреля 2011

Вы можете попробовать очистить поле пользователя в профессии:

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

Чтобы быть в безопасности, я бы также проверил, что переданный в профессии текущий пользователь равен this, на случай, если кто-то пройдетв профессии, принадлежащей другому пользователю.

0 голосов
/ 01 ноября 2013

Я только что добавил orphanRemoval = true в отношение OneToMany и решил его.

Класс 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;
...