Estou com dúvidas quando utilizo Jpa com Java. É meu primeiro tópico aqui.
Não entendo porque dá erro quando utilizo este código:
public class testeconexao {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EletricaPU");
EntityManager em = emf.createEntityManager();
Projeto projeto = new Projeto();
projeto.setNome("Chris");
projeto.setAutor("projeto");
projeto.setDescricao("teste");
projeto.setData(DataUtil.Atual());
em.getTransaction().begin();
em.persist(projeto);
em.getTransaction().commit();
Projeto projeto2 = projeto.clonarSemID();
em.getTransaction().begin();
em.persist(projeto2);
em.getTransaction().commit();
}
}
Exception in thread “main” javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86)
at teste.testeconexao.main(testeconexao.java:33)
Caused by: javax.persistence.PersistenceException: org.hibernate.HibernateException: identifier of an instance of br.aplicacao.eletrica.modelo.projeto.Projeto was altered from 1 to null
@Override
public Projeto clonarSemID() {
Projeto p = copiar();
p.setId(null);
return this;
}
@Override
public Projeto copiar() {
Projeto p = new Projeto();
p.setId(id);
p.setNome(nome);
p.setAutor(autor);
p.setData(data);
p.setDescricao(descricao);
for (Fonte f : fontes) {
p.fontes.add(f);
}
return this;
}
A forma como o JPA gerencia as entidades se baseia em manter uma referência a cada elemento, permitindo, então, identificar se este objeto é um novo objeto ou se é um objeto distinto.
Por alguma razão, o método clonarSemID mantém a referência do objeto em questão, apenas removendo seu ID. Coincidentemente, o ID é a PK do objeto, logo, não pode ser nula quando um objeto já está gerenciado pelo JPA.
Resolvido.
É necessário sempre criar uma nova instância.
public class testeconexao {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EletricaPU");
EntityManager em = emf.createEntityManager();
Projeto projeto = new Projeto();
projeto.setNome("Chris");
projeto.setAutor("projeto");
projeto.setDescricao("teste");
projeto.setData(DataUtil.Atual());
em.getTransaction().begin();
em.persist(projeto);
em.getTransaction().commit();
Projeto projeto2 = new Projeto();
projeto2.setNome(projeto.getNome());
projeto2.setAutor(projeto.getAutor());
projeto2.setDescricao(projeto.getDescricao());
projeto2.setData(projeto.getData());
em.getTransaction().begin();
em.persist(projeto2);
em.getTransaction().commit();
}
}
Acho que o Hibernate não entende como objeto novo fazendo dessa forma. Realmente não entendo. Ele copia a referencia do objeto anterior mesmo criando um novo dessa forma.
Usando o CloneSemID(), e comparando Projeto1 e Projeto2, o equals() retorna True!!!
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Projeto other = (Projeto) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
public class testeconexao {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EletricaPU");
EntityManager em = emf.createEntityManager();
Projeto projeto = new Projeto();
projeto.setNome("Chris");
projeto.setAutor("projeto");
projeto.setDescricao("teste");
projeto.setData(DataUtil.Atual());
em.getTransaction().begin();
em.persist(projeto);
em.getTransaction().commit();
Projeto projeto2 = projeto.clonarSemID();
System.out.println(projeto2.equals(projeto)); //true
em.getTransaction().begin();
em.persist(projeto2);
em.getTransaction().commit();
}
Não, não, não!
A instrução new sempre aloca uma nova região de memória, ou seja, é um novo objeto!
O problema é esse:
@Override
public Projeto copiar() {
Projeto p = new Projeto(); // Criou o objeto p
p.setId(id);
p.setNome(nome);
p.setAutor(autor);
p.setData(data);
p.setDescricao(descricao);
for (Fonte f : fontes) {
p.fontes.add(f);
}
return this; // mas retornou o objeto this
}