Como fazer um remove() no mapeamento @ManyToMany

13 respostas
alcemir

Bom dia!

Galera, alguém poderia me ajudar no mapeamento @ManyToMany?

Eu conseguir até salvar, mas na hora de fazer um remove() não estou conseguindo. Bom vou colocar um exemplo:

Aluno e Turma, o aluno tem muitas turmas dentro da sua vida escolar e a turma tem muitos alunos dentro do período letivo, ou seja, relacionamento @ManyToMany e bidirecional.

@Entity
@Table(name = "aluno")
public class Aluno implements Serializable {

    @ManyToMany(targetEntity=Turma.class,
                cascade = {CascadeType.ALL},
                mappedBy = "alunos", fetch = FetchType.EAGER)
    private Set<Turma> turmas;
}
@Entity
@Table(name = "turma")
public class Turma implements Serializable {

    @ManyToMany(targetEntity = Aluno.class, mappedBy="turmas",
    cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
    @JoinTable(name = "aluno_turma",
    joinColumns = {@JoinColumn(name = "idTurma")},
    inverseJoinColumns = {@JoinColumn(name = "idAluno")})
    private Set<Aluno> alunos;
}

Matriculando o aluno

@PersistenceContext
EntityManager em;

public void matricularAluno(Aluno aluno, Turma turma) {
        aluno.setMatriculado(true);
        aluno.getTurmas().add(turma);
        em.persist(em.merge(aluno));
        
        turma.getAlunos().add(aluno);
        em.persist(em.merge(turma));
    }

Desmatricular Aluno

Aqui é o problema, pois eu só tenho que desfazer o relacionamento, ou seja, retirar o aluno da lista da turma e retirar a turma da lista do aluno, e salvar, mas não estou conseguindo fazer. Alguém aí tem alguma idéia de como eu posso fazer isso?

13 Respostas

Lavieri
turma.getAlunos().remove(jose);

em.marge(turma);

// ^^
alcemir

já tentei, não vai não…

também achei que por ser bidirecional tem que fazer os dois lados na mesma transação, mas também já tentei e não consegui.

Já tentei também o em.persist(em.merge(aluno)), indo por turma, indo por aluno, pelos dois lados juntos, e nada… hehe…

não sei o que fazer, por isso estou pedindo ajuda à vocês…

alguém teria algum código exemplo de como fazer o persist, merge e remove no relacionamento ManyToMany?

Lavieri

aqui para mim funciona … O.o estranho… vou testar aqui e te falo o resultado

Lavieri

teste aqui e funciona… primeiro matriculei todos os alunos na turma de computação… olhei no banco e funcionou…

depois desmatriculei o 1° aluno, olhei no banoc, e funcionou tb… la embaixo ta o mapeamento das classes

public static void matricula() {
        List&lt;Aluno&gt; alunos = SESSION.createCriteria(Aluno.class).list();

        ATurma turma = (ATurma)SESSION
                .createCriteria(ATurma.class)
                .add(
                    Expression.eq("nome", "Computação")
                ).uniqueResult();

        turma.getAlunoCollection().addAll(alunos);

        for (Aluno aluno : turma.getAlunoCollection())
            System.out.println(aluno.getNome());

        ENTITY_MANAGER.getTransaction().begin();
        ENTITY_MANAGER.merge(turma);
        ENTITY_MANAGER.getTransaction().commit();
    }

    public static void desmatriculaOPrimeiro() {
        ATurma turma = (ATurma)SESSION
                .createCriteria(ATurma.class)
                .add(
                    Expression.eq("nome", "Computação")
                ).uniqueResult();
        turma.getAlunoCollection().remove(0);

        ENTITY_MANAGER.getTransaction().begin();
        ENTITY_MANAGER.merge(turma);
        ENTITY_MANAGER.getTransaction().commit();
    }

ALUNO

public class Aluno implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id") private Integer id; @Basic(optional = false) @Column(name = "nome") private String nome; @ManyToMany(mappedBy = "alunoCollection",cascade={CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REMOVE}) private List&lt;ATurma&gt; aTurmaCollection = new ArrayList&lt;ATurma&gt;(0);

TURMA

public class ATurma implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id") private Integer id; @Basic(optional = false) @Column(name = "nome") private String nome; @JoinTable(name = "a_matricula", inverseJoinColumns = {@JoinColumn(name = "aluno_id", referencedColumnName = "id")}, joinColumns = {@JoinColumn(name = "turma_id", referencedColumnName = "id")}) @ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REMOVE}) private List&lt;Aluno&gt; alunoCollection = new ArrayList&lt;Aluno&gt;(0);

alcemir

meu camarada, descobri o erro aqui...

fiz o debug e fui vendo a caminhada de variável por variável... então verifiquei que não está removendo o aluno da lista antes de dar um merge(), por isso não está alterando nada...

Tipo:
Desmatricular

@PersistenceContext
EntityManager em;

public void desmatricularAluno(Aluno aluno, Turma turma) {
        aluno.setMatriculado(false);
        aluno.getTurmas().remove(turma); // AQUI NÃO ESTÁ REMOVENDO, POR ISSO O EM.MERGE NÃO FAZ NADA
        em.merge(aluno);
        
        turma.getAlunos().remove(aluno); // MESMO CASO, NÃO ESTÁ REMOVENDO
        em.merge(turma);
    }

O que você acha que pode ser?

Lavieri
alcemir:
meu camarada, descobri o erro aqui...

fiz o debug e fui vendo a caminhada de variável por variável... então verifiquei que não está removendo o aluno da lista antes de dar um merge(), por isso não está alterando nada...

Tipo:
Desmatricular

@PersistenceContext
EntityManager em;

public void desmatricularAluno(Aluno aluno, Turma turma) {
        aluno.setMatriculado(false);
        aluno.getTurmas().remove(turma); // AQUI NÃO ESTÁ REMOVENDO, POR ISSO O EM.MERGE NÃO FAZ NADA
        em.merge(aluno);
        
        turma.getAlunos().remove(aluno); // MESMO CASO, NÃO ESTÁ REMOVENDO
        em.merge(turma);
    }

O que você acha que pode ser?

hashCode mau desenhado ... e equals mau desenhado... vc precisa implementar os 2, para as collections funcionarem perfeitamente...

leia esse artigo se tiver duvidas... => http://sergiotaborda.wordpress.com/java/colecoes-em-java/

caso keira ajuda, me fale os campos que identificam um ALUNO UNICO e uma TURMA UNICA ... para poder te ajudar com hashCode e com Equals...

alcemir

To passando o código, mas vou dar uma olhada no site. Se puder ajudar eu agradeço muito.

@Entity
@Table(name = "aluno")
public class Aluno implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String nome;
    private Boolean matriculado;
    @ManyToMany(targetEntity = Turma.class,
    mappedBy = "alunos",
    cascade = {CascadeType.PERSIST, CascadeType.MERGE},
    fetch = FetchType.EAGER)
    private Set<Turma> turmas = new HashSet<Turma>();
@Entity
@Table(name = "turma")
public class Turma implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String sigla;
    private String periodoLetivo;
    private String anoSerie;
    private String turno;
    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "idsegmento", referencedColumnName = "id")
    private Segmento segmento;
    @ManyToMany(targetEntity = Aluno.class,
    cascade = {CascadeType.MERGE, CascadeType.PERSIST}, fetch = FetchType.EAGER)
    private Set<Aluno> alunos = new HashSet<Aluno>();
Lavieri

como te falei, preciso saber o que torna um aluno UNICO e uma turma UNICA...

pelo que vi do seu aluno, apenas o código ID pode torna-lo único, visto que existem pessoas com mesmo nome... sendo assim

Para alunos:
public int hashCode() {
   hash = 0;
   hash = hash + (id == null) ? 0 : id.hashCode();
   return hash;
}

public boolean equals(Object o) {
    if (!o instanceof Aluno)
        return false;
    Aluno other = (Aluno)o;
    if ((this.id == null && other.id != null && !id.equals(other.id))
        return false;
    return true;
}
alcemir

ahhhh… o site tava explicando mas não mostro como fazia, agora entendi…

mas eu continuo fazendo o turmas.getAlunos.remove(aluno) ??

e como ficaria com mais de um atributo identificador?

vou testar aqui e já falo…

Lavieri

vc usa netbeans?? c usar é bem facil… apera ALT + INSERT … e escolhe hashCode e equals… depois seleciona os campos que juntos dão unique a sua classe e ele faz o hash e o equals…

e vc continua usando o id sim… so uma coisa… escrevi o equals errado ali… faltou um parentese… o equals é assim

public boolean equals(Object o) { if (!(o instanceof Aluno) ) return false; Aluno other = (Aluno)o; if ( (this.id == null && other.id != null) || (this.id != null && !id.equals(other.id)) ) return false; return true; }

alcemir

funcionou!!! to emocionado… hehe…

mas surgiu uma dúvida, em todas as classes entity é bom ter esses métodos?

Lavieri

alcemir:
funcionou!!! to emocionado… hehe…

mas surgiu uma dúvida, em todas as classes entity é bom ter esses métodos?

não em todo classe entity, sim em toda classe java heheh

agora sem trocadilhos, Toda classe é bom ter esses método bem definido, os métodos de Object

toString()
hashCode()
equals(Object o)

devem ser sobrescrito, a unica forma em java de testar se 2 objetos são iguais é através de object.equals(other);
object == other, não testa se são iguais, testa se apontam para o mesmo objeto…

hashCode é usado pra otimizar o processo de igualdade, pois todo objeto igual tem o mesmo hashCode, porem o contrario não é verdade, nem todo objeto com mesmo hashCode é igual… e como o hashCode usa int, ele é usado para verificar não igualdade de forma rapida…
if (object.hashCode() != other.hashCode()) então obrigatoriamente object e other serão diferentes…

toString é usado por diversar ferramentas para imprimir o objeto

portanto é sempre bom sobrescrever esses 3

Como toda regra tem sua exceção… Classes utilitaria de métodos estaticos que não serã instanciadas não precisam ter esses métodos implementados…

outras leituras relacionadas ao tema que vale a pena ler (Os 2 textos em portugues):

alcemir

Beleza, vou dar uma olhada!

Muito obrigado ai lavieri!!!

ajudou muito!

grande abraço!

Criado 23 de março de 2009
Ultima resposta 23 de mar. de 2009
Respostas 13
Participantes 2