在 Hibernate 中映射两个表 0..n

Posted

技术标签:

【中文标题】在 Hibernate 中映射两个表 0..n【英文标题】:Mapping two tables 0..n in Hibernate 【发布时间】:2010-02-24 15:16:03 【问题描述】:

我有一个用户表


CREATE TABLE "USERS" (
    "ID" NUMBER NOT NULL ,
    "LOGINNAME" VARCHAR2 (150) NOT NULL )

我还有第二张表 SpecialUsers。 SpecialUsers 表中的 UserId 不能出现两次,并且只有一小部分用户表中的用户 id 包含在 SpecialUsers 表中。


CREATE TABLE "SPECIALUSERS" (
    "USERID" NUMBER NOT NULL,
 CONSTRAINT "PK_SPECIALUSERS" PRIMARY KEY ("USERID") )

ALTER TABLE "SPECIALUSERS" ADD CONSTRAINT "FK_SPECIALUSERS_USERID" FOREIGN KEY ("USERID") 
REFERENCES "USERS" ("ID") 
/

在 Hibernate 中映射用户表可以正常工作


<hibernate-mapping package="com.initech.domain">
    <class name="com.initech.User" table="USERS">

        <id name="id" column="ID" type="java.lang.Long">
            <meta attribute="use-in-tostring">true</meta>
            <generator class="sequence">
                <param name="sequence">SEQ_USERS_ID</param>
            </generator>
        </id>

        <property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
            <meta attribute="use-in-tostring">true</meta>
        </property>

    </class>
</hibernate-mapping>

但我在为 SpecialUsers 表创建映射时遇到了困难。我发现 Internet 中的所有示例(例如在 Hibernate 文档中)都没有这种类型的自引用。我尝试了这样的映射:


<hibernate-mapping package="com.initech.domain">
    <class name="com.initech.User" table="SPECIALUSERS">        

        <id name="id" column="USERID">
            <meta attribute="use-in-tostring">true</meta>
            <generator class="foreign">
                <param name="property">user</param>
            </generator>
        </id>

        <one-to-one name="user" class="User"/>

    </class>
</hibernate-mapping>

但出现错误


Invocation of init method failed; nested exception is org.hibernate.DuplicateMappingException: 
Duplicate class/entity mapping com.initech.User 

我应该如何映射 SpecialUsers 表?我在应用程序级别需要的是包含在 SpecialUsers 表中的用户对象列表。

【问题讨论】:

为什么不在 USERS 表中添加一个“特殊”字段? 我考虑过,但考虑到“特殊”用户很少(目前只有一个)和很多用户,这似乎不对。从长远来看,如果每个仅适用于一小部分用户的小属性都将直接添加到用户表中,这也会使用户表不清楚。更进一步的原因是,如果“特殊”用户将来应该有更多与他们的“特殊性”相关的属性,很容易扩展 SpecialUsers 表。 为什么你认为某处存在 0..n 关系?您的物理模型没有反映这一点,它代表了一个纯粹的父子层次结构(即继承)。我错过了什么吗? @Pascal,如果您发现更好的描述,请随时更正标题。我猜逻辑是每个用户都有 0 到 1 个 SpecialUsers - 或者说,一些用户是特殊用户,但不是全部。 【参考方案1】:

我应该如何映射 SpecialUsers 表?

根据USERSSPECIALUSERS 表的结构,您有一个Table per subclass 层次结构,并且完全可以用Hibernate 映射这种层次结构

首先,确保SpecialUser在对象模型级别继承 User(这是一种继承关系,而不是自引用)。

public class SpecialUser extends User  

然后,在User 的映射中声明一个&lt;joined-subclass&gt; 元素:

<hibernate-mapping package="com.initech.domain">
    <class name="com.initech.User" table="USERS">

        <id name="id" column="ID" type="java.lang.Long">
            <meta attribute="use-in-tostring">true</meta>
            <generator class="sequence">
                <param name="sequence">SEQ_USERS_ID</param>
            </generator>
        </id>

        <property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
            <meta attribute="use-in-tostring">true</meta>
        </property>

        <joined-subclass name="com.initech.SpecialUser" table="SPECIALUSERS">
            <key column="USERID"/>
        </joined-subclass>

    </class>
</hibernate-mapping>

我在应用程序级别需要的是包含在 SpecialUsers 表中的用户对象列表。

以下 HQL 查询将返回所有 SpecialUser(也是 User):

from SpecialUser

如果以后需要在SPECIALUSERS 表中添加列,请将相应的属性添加到SpecialUser 类中,并将它们映射到&lt;joined-subclass&gt; 元素中。有关详细信息,请参阅提供的链接(指向文档)。

【讨论】:

【参考方案2】:

如果您确实必须使用第二个表,则必须将其映射到一个新类。 Hibernate 总是只能将一个表映射到一个类。

或者,在用户表中添加一列,其中显示“此用户很特殊”。如果这不是一个选项,请创建一个连接两个表的视图,从而模拟此列。然后,您可以通过此列选择用户。

如果您采用二分类方式,则必须加载特殊用户列表并在您的应用程序中进行映射。

[编辑] 也许你应该研究一下亲子关系。在您的情况下,用户是父母,其角色是孩子。因此,每个用户都有 0..n 个角色,这些角色映射在不同的表中。然后你可以使用这个 HQL

from User u where :role in elements(u.roles)

查找具有特定角色的所有用户。但大多数时候,你会有一个特定的用户,只需要查询她是否有某个角色。

【讨论】:

Aaroon,虽然问题的最初标题非常令人困惑,但我认为您的编辑并不反映最初的意图(它符合您的答案,但这不是 OP 要求恕我直言) .而且物理模型并不代表 0..n 关系顺便说一句,它是一个纯粹的继承关系。

以上是关于在 Hibernate 中映射两个表 0..n的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate 一个类映射到多个表

如何在同一个数据库表上映射两个 JPA 或 Hibernate 实体

Hibernate中用left join(左外连接)查询映射中没有关联关系的两个表记录问题

hibernate 组建映射 (两个表 合并成一张表)

Hibernate多对多关系映射(建表)

hibernate映射exception