Hibernate映射的情况,其中密钥也用作多对一参数

时间:2009-10-09 10:28:15

标签: java database hibernate orm

我想知道是否有办法对以下内容进行Hibernate映射。我花了两天时间就说没有。

有两个表,one to many关系。

+---------------------+       +-----------------+
|  versioned_entity   |       |  basic_entity   |
+---------------------+       +-----------------+
| fk_BasicEntityId    | *   1 | id              |
| version             |-------| active_version  |
| ...                 |       | ...             |
+---------------------+       +-----------------+

Hibernate映射:

<class name="my.VersionedEntity" table="versioned_entity">
  <composite-id>
    <key-many-to-one name="basicEntity" column="fk_BasicEntityId"/>
    <key-property name="version"/>
  </composite-id>
  ...
</class>

<class name="my.BasicEntity" table="basic_entity">
  <id name="id">
  <property name="activeVersion" not-null="true">
    <column name="active_version"/>
  </property>
  ...
</class>

简要说明:fk_BasicEntityId是指向basic_entity.id的外键。 versioned_entity中的条目可以通过其外键和version来标识(可以有许多版本具有相同的fk_BasicEntityId)。 active_version是一个指向versioned_entity个条目之一的数字,它告诉哪个版本是“活动的”。希望这很清楚。

现在我要解决的问题是我需要像Java这样快速访问Java:

my.BasicEntity basic = my.BasicEntityDAO.get();
my.VersionedEntity activeVersion = basic.getActiveVersionedEntity();

当前实现是在Java中完成的,只是迭代给定基本实体的所有版本化实体,并检查其版本是否与活动版本匹配。毋庸置疑,这不会扩展并导致性能问题。

所以我继续把它移到数据库级别。看起来容易?所以我认为!我接着将其添加到basic_entity的Hibernate映射中:

<many-to-one name="activeVersionedEntity" not-null="false" insert="false" update="false">
  <column name="id" unique="true" not-null="true"/>
  <column name="activeVersion"/>
</many-to-one>

此处需要双列,versioned_entity具有复合键。 不幸的是,这不起作用 - 当调用be.getActiveVersionedEntity()时,JVM会在没有跟踪的情况下死掉(在同事的机器上它会在Hibernate中抛出StackOverflowError)。我怀疑这是因为“id”也是一个标识符,因为我对同一个类的映射非常相似,其中列不是标识符,这可以正常工作。

我可以用HQL做到这一点,但这需要我将这个方法移到DAO类中,这特别笨拙,因为需要更改API(不是选项)。在my.BasicEntity::getActiveVersionedEntity()中使用DAO调用是另一个重要的禁忌:我不能混淆不同的抽象层。解决这个问题的另一种方法是调查拦截器/事件,但是这也可能是那些超出框架目的的选项之一(我不应该关心像这样的低级别事情,是吗?)。

我正在运行Hibernate版本:3.2.7GA / Spring 2.5.6。文档令人难以置信 - 我已经查看了三本不同的Hibernate书籍,在线文档,论坛等。

感谢任何帮助。

3 个答案:

答案 0 :(得分:1)

为什么将active_version映射为属性?我怀疑它是一个整数,对吧?为什么不将active_version更改为VersionedEntity类型?这样,这将是一个简单的一对一关系。

更新

我们正在为我们的某个网站使用此映射:

<many-to-one class="my.VersionedEntity" name="currentVersion" lazy="false" /> 

答案 1 :(得分:0)

听起来你正试图对某一列进行双重映射。我没有详细了解您的问题,但您是否考虑在其中一个映射上使用update = false和insert = false?这应该使您能够将同一列的双重映射作为关系和整数。更多信息here

答案 2 :(得分:0)

您是在建模双向引用关系还是继承层次结构?

如果对象模型是继承层次结构,则关系不应该是双向的,解决方案是从子类DAO获取子类实例。这消除了从基类导航到基类DAO中的子类的需要。这是我在原来的答案(下面)中试图解释的。

如果对象模型是双向关系,那么你需要在关系的“一”端的集合或包上设置inverse =“true” - 在本例中为BasicEntity。

Hibernate 3允许在关系的“一”端使用索引集合,但是带有set或bag的Hibernate 2功能应该足以测试理论。

此链接可能有所帮助:https://www.hibernate.org/193.html 另外:Hibernate Quickly pp142 - 145; Hibernate in Action pp108 - 111。


如果我正确理解了这个问题,你想从两个表中构建一个VersionedEntity,使用如下获得的数据:

select * from basic_entity be, versioned_entity ve where ve.id = be.id and ve.id = <id> and ve.active_version=<version>

鉴于你没有从另一个调用一个DAO的限制,我想知道所选方法是否正确表达了意图:

public my.VersionedEntity my.BasicEntityDAO.getActiveVersionedEntity();

你能否实现这样的方法:

public my.VersionedEntity my.VersionedEntityDAO.getActive();