@OneToOne + Table-per-Concrete-Class = исключение?

Я новичок в Hibernate, и я не могу получить @OneToOne функционировать в нашем коде.
После долгих чтений я создал отдельный пример и подумал о том, чтобы попросить помощи у сообщества.

Предположим, 3 класса: 1 абстрактный (Class_A) и 2 наследующих от него (Class_B / Class_C). Class_C имеет однонаправленный указатель на Class_B.
(Я подготовил диаграмму, но сайт не позволяет мне публиковать ее:-/).

Заметки:

  1. Чистая Java + Hibernate 3.6.0 Final + Oracle 11g.
  2. Стратегия наследования = Таблица для конкретного класса.
  3. Разработано с hibernate.hbm2ddl.auto=update,
  4. В нашем коде Class_B нужна собственная таблица, поэтому нет @Embeddable,
  5. В нашем коде 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();

Проблемы

  1. В insert(classC) Hibernate выдает только SQL для вставки Class_C. Нет SQL для вставки Class_B. Я вижу детали Class_C в Oracle, но таблица Class_B пуста.
    Вот SQL:

    Hibernate: вставить в Class_C (classB_myId, myString, myId) значения (?,?,?)

  2. В 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)
...

Вопросы пожалуйста

  1. Почему это не работает... что я делаю не так?
  2. В нашем устаревшем коде приложение распределяет уникальные номера идентификаторов и не собирается использовать сгенерированные идентификаторы. таким образом @GenerateValue за наших @Id не считается Это причина, почему это не удается?
  3. В чем разница между @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

Другие вопросы по тегам