Problema ao remover entidades da base de dados(Resolvido)

4 respostas
W

Pessoal, estou com um problema para remover as entidades na minha base de dados.

Eu possuo no banco de dados 3 entidades(Shopping, Loja e Produto), com um relacionamento um-para-muitos nesta mesma ordem.
Porém quando vou deletar um Shopping que possui uma loja, ou uma loja que possui muitos produtos, vejo o seguinte erro:

javax.ejb.EJBException: Transaction aborted

WARNING: Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERRO: atualização ou exclusão em tabela "shopping" viola restrição de chave estrangeira "fk_loja_shopping_id" em "loja"
  Detail: Chave (shopping_id)=(3) ainda é referenciada pela tabela "loja".
Error Code: 0
Call: DELETE FROM shopping WHERE (shopping_id = ?)
        bind => [3]
Query: DeleteObjectQuery(entities.Shopping@3)

O que eu queria é que quando eu removesse uma loja com produtos, os produtos desta loja automaticamente fossem removidos.
Eu até coloquei o atributo cascade = CascadeType.ALL na anotação das entidades, achei que isso era a solução, mas o problema persiste ainda.
Estou usando o NetBeans 6.8, JPA 2.0.

O que faço? Agradeço desde já a atenção.

4 Respostas

F

Olá Will_HRock!

Não sei se é o caso, você não mandou seu código, mas é muito provável que você não tenha configurado suas entidades para aplicar as alterações em cascata. Então, ou vc exclui as entidades na ordem de forma a não causar o conflito, ou então adiciona na anotação do relacionamento como no exemplo:

@OneToMany(cascade=ALL)

Adicionando ALL será aplicado às entidades associadas todas as operações (INSERT, UPDATE, DELETE) de forma implícita.

Fazendo uma busca rápida, encontrei o artigo http://www.theserverside.com/tt/articles/article.tss?l=JPAObjectModel. Pode ajudar.

Abraços!

Fábio Braga de Oliveira
http://www.smallthoughts.com.br

F

Nossa, Will, desculpe a minha falha.

Acho que não acordei ainda, não vi a segunda parte da sua mensagem, onde vc dizia que já colocou o cascade.ALL.

No caso, tô sem pistas… Pode publicar seu código?

Como eu queria poder apagar uma mensagem… maldito dedo rápido…

W

Esse é o código da entidade Loja:

package entities;

import java.util.*;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import java.io.Serializable;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@Table(name = "loja")
@SequenceGenerator(name = "LOJA_SEQUENCE", sequenceName = "loja_seq", initialValue = 30,
                   allocationSize = 1)
@NamedQueries({
    @NamedQuery(name = "Loja.buscarTodas", query = "SELECT l FROM Loja l"),
    @NamedQuery(name = "Loja.buscarPorNomeID",
                query = "SELECT l FROM Loja l INNER JOIN l.shoppingId s WHERE l.nome LIKE " +
                ":nomeLoja AND s.shoppingId = :shopId")})
@Entity
public class Loja implements Serializable {
    @Id
    @Basic(optional = false)
    @Column(name = "loja_id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "LOJA_SEQUENCE")
    private Long lojaId;
    @Basic(optional = false)
    @Column(name = "nome")
    private String nome;
    @Column(name = "andar")
    private Integer andar;
    @Column(name = "telefone")
    private String telefone;
    @XmlTransient
    @OneToMany(mappedBy = "loja", cascade = CascadeType.ALL)
    private List<Produto> produtos;
    @JoinColumn(name = "shopping_id", referencedColumnName = "shopping_id")
    @ManyToOne
    @XmlTransient
    private Shopping shoppingId;

    public Loja() {}
    public Loja(Long lojaId) { this.lojaId = lojaId; }

    public Loja(Long lojaId, String nome) {
        this.lojaId = lojaId;
        this.nome = nome;
    }

    public Loja(String nome, int andar, String telefone, Shopping shopping) {
        this.nome = nome;
        this.andar = andar;
        this.telefone = telefone;
        this.shoppingId = shopping;
    }

    public Long getLojaId() { return lojaId; }
    public void setLojaId(Long lojaId) { this.lojaId = lojaId; }

    public String getNome() { return nome; }
    public void setNome(String nome) { this.nome = nome; }

    public Integer getAndar() { return andar; }
    public void setAndar(Integer andar) { this.andar = andar; }

    public String getTelefone() { return telefone; }
    public void setTelefone(String telefone) { this.telefone = telefone; }

    public List<Produto> getProdutos() { return produtos; }
    public void setProdutos(List<Produto> produtos) { this.produtos = produtos; }

    public Shopping getShoppingId() { return shoppingId; }
    public void setShoppingId(Shopping shoppingId) { this.shoppingId = shoppingId; }

    public void addProduto(Produto produto) { produtos.add(produto); }
    public void removerProduto(Produto produto) { produtos.remove(produto); }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (lojaId != null ? lojaId.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Loja)) {
            return false;
        }
        Loja other = (Loja) object;
        if ((this.lojaId == null && other.lojaId != null) || (this.lojaId != null && !this.lojaId.equals(other.lojaId))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "Loja: " + getNome() + "; ID:" + this.getLojaId() + "; Telefone: "
                + getTelefone();
    }
}

Eu consegui um workaround no método que persiste minha entidade, fazendo o Shopping referenciar a entidade loja ao mesmo tempo que a loja referencia o shopping, assim:

@Interceptors({LojaValidadorInterceptor.class})
    public void criar(Loja loja) throws EntidadeException {
        em.persist(loja);
        Shopping shopping = loja.getShoppingId();
        shopping.addLoja(loja);
    }

Não sei se é o jeito mais correto mas funcionou, se souber de algo melhor que eu possa fazer agradeço! valeu!

F

Will, você está usando o EclipseLink com o JPA 2.0, certo? Você está fazendo o weaving das classes? Num projeto meu aqui, eu uso maven e faço weaving estático, pra funcionar eu adicionei no pom.xml:

&lt;build&gt;
	&lt;plugins&gt;
		&lt;artifactId&gt;maven-antrun-plugin&lt;/artifactId&gt;
		&lt;executions&gt;
			&lt;execution&gt;
				&lt;phase&gt;process-classes&lt;/phase&gt;
				&lt;configuration&gt;
					&lt;tasks&gt;
						&lt;java classname="org.eclipse.persistence.tools.weaving.jpa.StaticWeave" classpathref="maven.runtime.classpath" fork="true"&gt;
						&lt;arg line="-loglevel FINE -persistenceinfo src/main/resources target/classes target/classes" /&gt;
						&lt;/java&gt;
					&lt;/tasks&gt;
				&lt;/configuration&gt;
				&lt;goals&gt;
					&lt;goal&gt;run&lt;/goal&gt;
				&lt;/goals&gt;
			&lt;/execution&gt;
		&lt;/executions&gt;
	        &lt;/plugin&gt;
       &lt;/plugins&gt;
&lt;/build&gt;

e no persistence.xml:

&lt;properties&gt;
            &lt;property name="eclipselink.target-database" value="Auto" /&gt;
            &lt;property name="eclipselink.logging.level" value="INFO" /&gt;
            &lt;property name="eclipselink.weaving" value="static" /&gt;
&lt;/properties&gt;

Se não estiver fazendo weaving, tenta e fala o resultado. Boa sorte!

Criado 18 de fevereiro de 2010
Ultima resposta 18 de fev. de 2010
Respostas 4
Participantes 2