@OneToOne + Table-per-Concrete-Class =例外?

时间:2011-02-15 15:57:54

标签: hibernate one-to-one ora-02291

我是Hibernate的新手,我无法让@OneToOne在我们的代码中运行 经过多次阅读,我构建了一个隔离区示例,并考虑向社区提供帮助。

假设有3个类:1个抽象(Class_A)和2个继承自它的类(Class_B / Class_C)。 Class_C有一个指向Class_B的单向指针 (我已经准备了一个图表,但该网站不会让我发布它: - /)。

注意:

  1. Pure Java + Hibernate 3.6.0 Final + Oracle 11g。
  2. 继承策略= 每个具体类的表
  3. 使用hibernate.hbm2ddl.auto=update开发。
  4. 在我们的代码中,Class_B需要自己的表,因此没有@Embeddable
  5. 在我们的代码中,Class_C也是抽象的,不像简化示例中所示。
  6. 代码

    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代码

    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。我在Oracle中看到Class_C的详细信息,但Class_B的表是空的 这是SQL:

        

      Hibernate:插入Class_C(classB_myId,myString,myId)值(?,?,?)

    2. getTransaction().commit(),它会以

    3. 爆炸

      这样:

      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. 在我们的遗留代码中,应用程序分配唯一的ID号,并且无意使用生成的ID。因此,我们@GenerateValue的{​​{1}}不予考虑。这是失败的原因吗?
      3. @Id@OneToOne(cascade = CascadeType.ALL) + @OneToOne之间的区别是什么?
      4. 非常感谢!

        • Ten_of_a_Kind

2 个答案:

答案 0 :(得分:0)

我猜原因是

StatelessSession statelessSession = sessionFactory.openStatelessSession(); 

尝试使用普通Session代替:

Session session = sessionFactory.openSession(); 

StatelessSession是一种特殊目的工具,只能在特殊情况下使用。对于常规操作,您应始终使用Session。来自Hibenrate文档:

  

或者,Hibernate提供了一个面向命令的API,可用于以分离对象的形式将数据流入和流出数据库。 StatelessSession没有与之关联的持久性上下文,也没有提供许多更高级别的生命周期语义。特别是,无状态会话不实现第一级缓存,也不与任何第二级或查询缓存交互。它不实现事务性后写或自动脏检查。 使用无状态会话执行的操作永远不会级联到关联的实例。

答案 1 :(得分:0)

请检查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进行测试