Reputation: 61
I'm new to Hibernate, and I can't get @OneToOne
to function in our code.
After much reading, I've constructed an isolates example, and thought to ask the help of the community.
Suppose 3 classes: 1 abstract (Class_A) and 2 inheriting from it (Class_B / Class_C). Class_C has a unidirectional pointer to Class_B.
(I've prepared a diagram but the site wont let me post it :-/).
Notes:
hibernate.hbm2ddl.auto=update
.@Embeddable
.Class_A
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Class_A {
@Id
public long myId = 0;
}
Class_B
@Entity
@Table(name = "Class_B")
public class Class_B extends Class_A {
private String myString = "Hellos - I'm Class_B!";
}
Class_C
@Entity
@Table(name = "Class_C")
public class Class_C extends Class_A {
private String myString = "Hellos - I'm Class_C!";
@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@NotNull
private Class_B classB;
public void setClassB(Class_B classB) {
this.classB = classB;
}
}
Hibernate Code
StatelessSession statelessSession = sessionFactory.openStatelessSession();
Class_C classC = new Class_C();
classC.myId = 92;
Class_B classB = new Class_B();
classB.myId = 8000;
classC.setClassB(classB);
statelessSession.beginTransaction();
statelessSession.insert(classC);
statelessSession.getTransaction().commit();
statelessSession.close();
At insert(classC)
Hibernate only issues an SQL to insert Class_C. There is no SQL to insert Class_B. I see Class_C's details in Oracle, but Class_B's table is empty.
Here's the SQL:
Hibernate: insert into Class_C (classB_myId, myString, myId) values (?, ?, ?)
At getTransaction().commit()
it explodes with
this:
java.sql.BatchUpdateException: ORA-02291: integrity constraint (NDP.FK9619CF1CAD47EF0F) violated - parent key not found
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:17660)
at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:771)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
at org.hibernate.impl.StatelessSessionImpl.managedFlush(StatelessSessionImpl.java:333)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
...
@GenerateValue
for our @Id
isn't considered. Is this a reason why this fails?@OneToOne(cascade = CascadeType.ALL)
vs. @OneToOne
+ @Cascade({CascadeType.ALL})
?MUCH thanks!
Upvotes: 0
Views: 781
Reputation: 59
Please check Hibernate docs. As stated there:
Operations performed using a stateless session never cascade to associated instances. http://docs.jboss.org/hibernate/core/3.3/reference/en-US/html/batch.html#batch-statelesssession
With org.hibernate.StatelessSession, you have deal with object inter-dependencies when inserting objects. That's not the case when you are using a org.hibernate.Session.
In this case, you must persist classB object before classC object to make it work. Persisting order do counts. If you change the persistence order you will have org.hibernate.exception.ConstraintViolationException. Choose carefully when to use stateless sessions, as it has no persistence context.
statelessSession.beginTransaction();
statelessSession.insert(classB); // <- Persisting classB
statelessSession.insert(classC);
statelessSession.getTransaction().commit();
statelessSession.close();
Tested with Hibernate 3.6.0 Final + MySQL 5.0.51a-24
Upvotes: 0
Reputation: 242706
I guess the cause is
StatelessSession statelessSession = sessionFactory.openStatelessSession();
Try to use a normal Session
instead:
Session session = sessionFactory.openSession();
StatelessSession
is a special purpose tool that should be used only in special circumstances. For regular operations you should always use Session
. From Hibenrate docs:
Alternatively, Hibernate provides a command-oriented API that can be used for streaming data to and from the database in the form of detached objects. A StatelessSession has no persistence context associated with it and does not provide many of the higher-level life cycle semantics. In particular, a stateless session does not implement a first-level cache nor interact with any second-level or query cache. It does not implement transactional write-behind or automatic dirty checking. Operations performed using a stateless session never cascade to associated instances.
Upvotes: 0