Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp
Hello, i am confused to work with a SIMPLE Parent/Child relationship... (all information need is along the post..)
first: The PERSIST operation do not cascade to Children (Alternativas) when i call entityManager.persit(pergunta). You can see that only one SQL is generated inserting the Object Pergunta
second: what is exactly the semantics of cascade atribute. As annotated in my entities it means that: 1. ALL operations when applied to Pergunta will cascade to Alternativas; 2. The operations PERSIST and MERGE when applied to Alternativa will cascade to its Parent (Pergunta)? correct?
third: why the hell when i change the
Code between sessionFactory.openSession() and session.close(): to this one:
public void testInsertPerguntaComAlternativas() {
Pergunta p = new Pergunta();
PerguntaHome dao = PerguntaHome.getInstance();
try {
dao.persist(p);
Alternativa a1 = new Alternativa(p, "4");
Alternativa a2 = new Alternativa(p, "6");
//adiciona as alternativas
p.addAlternativa(a1);
p.addAlternativa(a2);
//seta a alternativa correta
p.setGabarito(a1);
Pergunta p2 = dao.findById(p.getId());
assertNotNull(p2);
assertTrue(p2.getAlternativas().size() == 2);
..... .... ....
} catch (RuntimeException e) {
fail("Nao deveria lancar excecao: "+e.getMessage());
}
}
It do not throw any Exception and give no errors (the Unit Test pass OK) but only generate only one statement (inserting Pergunta only and not the two children (Alternativas a1 and a2).
When I see the data on database tables (Using SQLYog) there is 1 registry for Pergunta but none for Alternativa.
Can anyone explain how i need to manage the persistence of a parent child relationship? pliz.. thanks ALL...
Hibernate version: 3.2
Mapping documents (Using Annotations):
Pergunta.java
@Entity
@Table(name = "pergunta", catalog = "jogoconcurso", uniqueConstraints = {})
public class Pergunta implements java.io.Serializable {
...
@Id @GeneratedValue(strategy=GenerationType.AUTO)
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
....
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, mappedBy = "pergunta")
public Set<Alternativa> getAlternativas() {
return this.alternativas;
}
//I really dont know why i did this...(perhaps trying to solve the problem.. but..)
public void setAlternativas(Set<Alternativa> alternativas) {
if(alternativas != null && alternativas.size() > 0) {
this.alternativas = new HashSet<Alternativa>();
for (Alternativa a : alternativas) {
addAlternativa(a);
}
}
}
//again.. trying to solve the problem... but...
public void addAlternativa(Alternativa a) {
//manually assiging IDs...
a.setId(this.alternativas.size() + 1);
a.setIdPergunta(this.getId());
//sets relationship (Alternativa-Pergunta)
a.setPergunta(this);
//Sets relationship (Pergunta-Alternativa)
if(!this.alternativas.contains(a))
this.alternativas.add(a);
}
....
Alternativa.java
@Entity
@Table(name = "alternativa", catalog = "jogoconcurso", uniqueConstraints = {})
@IdClass(AlternativaId.class) //alterado a geracao de Ids
public class Alternativa implements java.io.Serializable, Comparable<Alternativa> {
...
// Id assigned manually (dont know how to AUTO assign Composite Ids..)
@Id
@Column(name = "id", unique = false, nullable = false, insertable = true, updatable = true)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
@JoinColumn(name = "id_pergunta", unique = false, nullable = false, insertable = false, updatable = false)
public Pergunta getPergunta() {
return this.pergunta;
}
public void setPergunta(Pergunta pergunta) {
this.pergunta = pergunta;
}
...
AlternativaId.java
@Embeddable
public class AlternativaId implements java.io.Serializable {
...
@Column(name = "id", unique = false, nullable = false, insertable = true, updatable = true)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
@Column(name = "id_pergunta", unique = false, nullable = false, insertable = false, updatable = false)
public int getIdPergunta() {
return this.idPergunta;
}
public void setIdPergunta(int idPergunta) {
this.idPergunta = idPergunta;
}
...
}
PerguntaHome.java
@Stateless
public class PerguntaHome {
private static final Log log = LogFactory.getLog(PerguntaHome.class);
private static PerguntaHome singleton = null;
@PersistenceContext
private EntityManager entityManager;
private PerguntaHome() {
entityManager = StandaloneEntityManagerFactory.newEntityManager();
}
public static synchronized PerguntaHome getInstance() {
if(singleton == null)
singleton = new PerguntaHome();
return singleton;
}
public synchronized void persist(Pergunta transientPergunta) {
log.debug("persisting Pergunta instance");
EntityTransaction t = entityManager.getTransaction();
try {
t.begin();
entityManager.persist(transientPergunta);
System.out.println("PerguntaHome.persist() ID pergunta "+transientPergunta.getId());
log.debug("persist successful");
t.commit();
} catch (RuntimeException re) {
log.error("persist failed", re);
t.rollback();
throw re;
}
}
....
}
StandaloneEntityManagerFactory.java
public class StandaloneEntityManagerFactory {
private static final EntityManagerFactory factory;
static {
factory = Persistence.createEntityManagerFactory("AppEntityManager");
}
public StandaloneEntityManagerFactory() {
}
public static synchronized EntityManager newEntityManager() {
return factory.createEntityManager();
}
Code between sessionFactory.openSession() and session.close():
public void testInsertPerguntaComAlternativas() {
Pergunta p = new Pergunta();
PerguntaHome dao = PerguntaHome.getInstance();
try {
Alternativa a1 = new Alternativa(p, "4");
Alternativa a2 = new Alternativa(p, "6");
//adiciona as alternativas
p.addAlternativa(a1);
p.addAlternativa(a2);
//seta a alternativa correta
p.setGabarito(a1);
dao.persist(p);
Pergunta p2 = dao.findById(p.getId());
assertNotNull(p2);
assertTrue(p2.getAlternativas().size() == 2);
..... .... ....
} catch (RuntimeException e) {
fail("Nao deveria lancar excecao: "+e.getMessage());
}
}
Full stack trace of any exception that occurs:
javax.persistence.RollbackException: Error while commiting the transaction
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:63)
at jogo.persistence.dao.PerguntaHome.persist(PerguntaHome.java:52)
at teste.persistence.dao.PerguntaHomeTest.testInsertPerguntaComAlternativas(PerguntaHomeTest.java:121)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.hibernate.HibernateException: identifier of an instance of jogo.model.Alternativa was altered from id: 1, id_pergunta: 0 to id: 1, id_pergunta: 30
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:58)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:157)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:113)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:53)
... 18 more
Name and version of the database you are using:MySQL, version: 5.0.27-community-nt
The generated SQL (show_sql=true):
Hibernate: insert into jogoconcurso.pergunta (id_materia, id_submetedor, enunciado, id_autor, situacao) values (?, ?, ?, ?, ?)
Debug level Hibernate log excerpt:
Problems with Session and transaction handling?
Read this:
http://hibernate.org/42.html