@OneToOne +每个具体类表 = 例外?

发布于 2024-10-17 21:37:57 字数 3107 浏览 9 评论 0原文

我是 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;
    }
}

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

    <块引用>

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

  2. At 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. 在我们的遗留代码中,应用程序分配唯一的 ID 号,并且无意使用生成的 ID。因此,我们的 @Id@GenerateValue 不会被考虑。这是失败的原因吗?
  3. @OneToOne(cascade = CascadeType.ALL)@OneToOne + @Cascade({CascadeType.ALL}) 有什么区别?

非常感谢!

  • 十种

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:

  1. Pure Java + Hibernate 3.6.0 Final + Oracle 11g.
  2. Inheritance strategy = Table per Concrete Class.
  3. Developed with hibernate.hbm2ddl.auto=update.
  4. In our code Class_B needs its own table, thus no @Embeddable.
  5. In our code Class_C is also abstract, not as presented here in the simplified example.

Code

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();

Problems

  1. 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 (?, ?, ?)

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

Questions Please

  1. Why doesn't this work... what am I doing wrong?
  2. In our legacy code, the application allocates unique id numbers and have no intention of using generated Ids. Thus @GenerateValue for our @Id isn't considered. Is this a reason why this fails?
  3. Whats the difference between @OneToOne(cascade = CascadeType.ALL) vs. @OneToOne + @Cascade({CascadeType.ALL})?

MUCH thanks!

  • Ten_of_a_Kind

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温馨耳语 2024-10-24 21:37:57

我猜原因是

StatelessSession statelessSession = sessionFactory.openStatelessSession(); 

尝试使用普通的 Session 来代替:

Session session = sessionFactory.openSession(); 

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

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

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.

空袭的梦i 2024-10-24 21:37:57

请检查 Hibernate 文档。正如那里所说:

使用无状态会话执行的操作永远不会级联到关联的实例。
http://docs.jboss .org/hibernate/core/3.3/reference/en-US/html/batch.html#batch-statelesssession

使用org.hibernate.StatelessSession,您可以处理对象之间的依赖关系插入对象时。当您使用 org.hibernate.Session 时,情况并非如此。

在这种情况下,您必须将 B 类对象保留在 C 类对象之前才能使其工作。坚持订单很重要。如果更改持久性顺序,将会出现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 进行测试

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文