@OneToOne + Table-per-Concrete-Class = исключение?
Я новичок в Hibernate, и я не могу получить @OneToOne
функционировать в нашем коде.
После долгих чтений я создал отдельный пример и подумал о том, чтобы попросить помощи у сообщества.
Предположим, 3 класса: 1 абстрактный (Class_A) и 2 наследующих от него (Class_B / Class_C). Class_C имеет однонаправленный указатель на Class_B.
(Я подготовил диаграмму, но сайт не позволяет мне публиковать ее:-/).
Заметки:
- Чистая Java + Hibernate 3.6.0 Final + Oracle 11g.
- Стратегия наследования = Таблица для конкретного класса.
- Разработано с
hibernate.hbm2ddl.auto=update
, - В нашем коде Class_B нужна собственная таблица, поэтому нет
@Embeddable
, - В нашем коде Class_C также является абстрактным, а не представленным здесь в упрощенном примере.
Код
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;
}
}
Код гибернации
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();
Проблемы
В
insert(classC)
Hibernate выдает только SQL для вставки Class_C. Нет SQL для вставки Class_B. Я вижу детали Class_C в Oracle, но таблица Class_B пуста.
Вот SQL:Hibernate: вставить в Class_C (classB_myId, myString, myId) значения (?,?,?)
В
getTransaction().commit()
это взрывается с
этот:
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
за наших@Id
не считается Это причина, почему это не удается? - В чем разница между
@OneToOne(cascade = CascadeType.ALL)
против@OneToOne
+@Cascade({CascadeType.ALL})
?
Большое спасибо!
- Ten_of_a_Kind
2 ответа
Я думаю, причина в том,
StatelessSession statelessSession = sessionFactory.openStatelessSession();
Попробуйте использовать нормальный Session
вместо:
Session session = sessionFactory.openSession();
StatelessSession
это инструмент специального назначения, который следует использовать только в особых обстоятельствах. Для регулярных операций вы всегда должны использовать Session
, Из документов Hibenrate:
В качестве альтернативы Hibernate предоставляет командно-ориентированный API, который можно использовать для потоковой передачи данных в базу данных и из нее в виде отдельных объектов. StatelessSession не имеет связанного с ним персистентного контекста и не предоставляет много семантики жизненного цикла более высокого уровня. В частности, сеанс без сохранения состояния не реализует кэш первого уровня и не взаимодействует ни с каким вторым уровнем или кешем запросов. Он не реализует транзакционную запись или автоматическую грязную проверку. Операции, выполняемые с использованием сеанса без сохранения состояния, никогда не касаются связанных экземпляров.
Пожалуйста, проверьте документы Hibernate. Как указано там:
Операции, выполняемые с использованием сеанса без сохранения состояния, никогда не касаются связанных экземпляров. http://docs.jboss.org/hibernate/core/3.3/reference/en-US/html/batch.html
С org.hibernate.StatelessSession вы имеете дело с взаимозависимостями объектов при вставке объектов. Это не тот случай, когда вы используете org.hibernate.Session.
В этом случае вы должны сохранить объект classB перед объектом classC, чтобы он работал. Сохраняющийся порядок имеет значение. Если вы измените порядок сохранения, у вас будет org.hibernate.exception.ConstraintViolationException. Тщательно выбирайте, когда следует использовать сеансы без сохранения состояния, так как он не имеет постоянного контекста.
statelessSession.beginTransaction();
statelessSession.insert(classB); // <- Persisting classB
statelessSession.insert(classC);
statelessSession.getTransaction().commit();
statelessSession.close();
Протестировано с Hibernate 3.6.0 Final + MySQL 5.0.51a-24