@OneToOne + Table-per-Concrete-Class = исключение? - PullRequest
0 голосов
/ 15 февраля 2011

Я новичок в 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 ]

0 голосов
/ 15 февраля 2011

Пожалуйста, проверьте документы Hibernate.Как там указано:

Операции, выполняемые с использованием сеанса без сохранения состояния, никогда не каскадно связываются с экземплярами.http://docs.jboss.org/hibernate/core/3.3/reference/en-US/html/batch.html#batch-statelesssession

С 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

0 голосов
/ 15 февраля 2011

Я думаю, причина

StatelessSession statelessSession = sessionFactory.openStatelessSession(); 

Попробуйте использовать обычный Session вместо:

Session session = sessionFactory.openSession(); 

StatelessSession - это инструмент специального назначения, который следует использовать только в особых случаях. Для регулярных операций вы всегда должны использовать Session. Из документов Hibenrate:

В качестве альтернативы, Hibernate предоставляет командно-ориентированный API, который можно использовать для потоковой передачи данных в базу данных и из нее в виде отдельных объектов. StatelessSession не имеет связанного с ним персистентного контекста и не предоставляет много семантики жизненного цикла более высокого уровня. В частности, сеанс без сохранения состояния не реализует кэш первого уровня и не взаимодействует с кешем второго уровня или запроса. Он не реализует транзакционную запись или автоматическую грязную проверку. Операции, выполняемые с использованием сеанса без сохранения состояния, никогда не касаются связанных экземпляров.

...