使用Hibernate将两个表映射到一个实体。

18

我有一个实体 - User。它通过User.class来描述。

Hibernate为每个实体创建一个表,因此当我调用session.save(user)时,我的数据总是保存在这个表中。

现在我需要另一个表来存储相同User类型的数据,并且我只需要将我的实体保存到那个表中。

数据结构(类似于这样):

table users_1_table{
  string id;
  string username;
}

table users_2_table{
  string id;
  string username;
}

与此合作:

session.save(user1,"users_1_table")
session.save(user2,"users_2_table")

最终结果应该在users_1_table中有user1,并且在users_2_table中有user2

由于系统限制,我不能将这两个对象放在同一张表格中(即使创建额外的字段也不是一个好主意)。

我能否在不使用子类化的情况下完成这个操作?可以使用程序化的Hibernate配置吗?


1
为什么你想在不使用子类化的情况下这样做?子类化是Hibernate的解决方案。如果你想在不使用子类化的情况下这样做,那么你正在使用错误的工具。 - Danubian Sailor
5个回答

36

前言:

这是一个在SO上经常被问到的问题,答案通常与子类(Subclass)或实际上是超类(SuperClass)方法有关(例如[1])。

实际答案:

在这些帖子中[2],[3]他们建议使用带有EntityName参数的xml映射。

因此,使用xml映射不需要超类,只需将EntityName参数提供给两个相同的映射即可。

示例映射:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
   <class name="DomainModel.User, DomainModel"
     table="User1Object" entity-name="User1Object">  
         <id name="_id" access="field" column="id">
             <generator class="assigned"/>
         </id>
        <property name= ...>
 </class>
 <class name="DomainModel.User, DomainModel"
     table="User2Object" entity-name="User2Object">
         <id name="_id" access="field" column="id">
            <generator class="assigned"/>
         </id>
        <property name= ...>
</class>
</hibernate-mapping>

根据需要的实体类型,您可以调用相应的会话方法,如:

_session.Save("User1Object", user1)

或者

_session.Save("User2Object", user2)

这个片段是基于帖子2和3创建的。官方来源[4]

匹配后:

第一个问题的一个答案实际上链接到这篇文章[5],有不同的方法:

您告别对象的第一个实例,将数据克隆到新实例并使用不同名称持久化。因此,没有违反Hibernate逻辑,每个人都满意:在两个表中具有相同的数据且没有使用子类。

好吧,该方法的实现、代码或可信度都还好,我也没有测试过。

另一种情况:

在这篇文章[6]中,有另一个人试图用更简单的方法挑战超类方法,但最可靠的答案仍然是无法绕过官方非XML方法,即所谓的子类方法。
来源:
[1] 如何使用Hibernate/JPA注释将一个类映射到不同的表格 [2] 在Hibernate中将两个相同的表(相同模式...)映射到同一实体 [3] 如何将2个相同的表(相同属性)映射到1个实体

[4] http://docs.jboss.org/hibernate/core/3.2/reference/en/html/mapping.html#mapping-entityname}

[5] Hibernate 4:一个类映射两个表 - 如何将一个对象保存在两个表中?

[6] 用于存在于多个目录中的实体的Hibernate注释


能否在Eclipse中生成它? - Vishnudev K
Eclipse网站(http://www.myeclipseide.com/documentation/quickstarts/hibernate/#5-7)有一个指令表,其中包括其反向工程工具,并带有选项“创建抽象类”,其说明为*“为每个数据对象生成抽象超类。这些抽象类将在后续的生成过程中被覆盖,但相应的子类不会被覆盖。”* 在我看来,这可以生成至少一些有用的东西。 - mico
如果实体B是A和C的成员(多对一),而我保存A和C的实例,而不是直接保存B,那么我需要做什么? - Kuldeep Yadav
在这种情况下,选择查询会如何工作?假设我使用此方法将实体映射到两个不同的表,这两个表仅相差一列,现在我想从这两个表中获取所有行,我是否需要使用某种连接查询,还是它会自动获取这两个表中的行? - Ghos3t

4
此功能可以使用默认实体和备用实体进行操作:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
   <class name="DomainModel.User, DomainModel"
     table="User1Object">  
         <id name="_id" access="field" column="id">
             <generator class="assigned"/>
         </id>
        <property name= ...>
 </class>
 <class name="DomainModel.User, DomainModel"
     table="User2Object" entity-name="User2Object">
         <id name="_id" access="field" column="id">
            <generator class="assigned"/>
         </id>
        <property name= ...>
</class>
</hibernate-mapping>

对于默认的情况,您可以使用以下方法:

_session.Save(user1)

并且

_session.Save("User2Object", user2)

为了使用另一种替代方案。

1
您可以使用配置来完成此操作:
  • 为相同的实体类name创建两个映射,但为它们分配不同的逻辑entity-nametable名称。
  • 然后使用提供entityName参数的Session方法来区分其中一个。

这样做有什么作用?

  • 虚拟子类型
  • 当将数据检索到类型中时,必须指定其中一个实体类型(从而暗示着一个表或另一个表)
  • 当修改数据并保存它时,必须指定相同的实体类型 - 尝试使用不同的实体类型更新应该被Hibernate拒绝。否则,已修改的实体将已经有一个标识符填充,因此Hibernate将尝试更新而不是插入,但这将在数据库中失败 - 企图更新从未存在于表格中的数据。
  • 这导致分离 - 在处理实体或实体列表时,必须承诺一种实体类型,并且不能混合使用两种类型。即“虚拟子类型”

成本是多少?

  • 它提供了非常弱的类型。编译器和运行时没有真实子类型的指示。错误正在等待发生,可能很难调试。
  • 它是非标准的。JPA已经避开了这个问题,我认为它不在考虑范围内,理由充分。
  • 您必须使用XML而不是注释。
  • 您必须调用不寻常的方法,包括“entity-type”参数。

与子类型相比是否有好处?

  • 我看不出任何好处

你应该这样做吗?

  • 我认为不应该!使用子类型和标准代码。

0

我知道这个问题很久以前就被问过了。但是我想提供一种替代方法,而不使用任何Hibernate的东西。对于那些不想使用XML配置的人来说。

声明一个接口,其中包含公共列的getter和setter方法,然后使您的两个实体类实现此接口。 将这两个实体类中的映射注释保留为通常状态,然后在您的代码中,您可以调用此接口的方法。


0

虽然我从未使用过,但在Hibernate中有一个名为Secondary Table的概念。而@SecondaryTables是Hibernate中的注解,通过它,实体可以映射多个表来获取数据。获取数据的实体应该具有@SecondaryTables注解。它基于主键、外键和唯一约束将辅助表与主表关联起来。

这里是我在谷歌上找到的一个示例,看看它是否能帮助你实现:

http://www.concretepage.com/hibernate/secondarytables_hibernate_annotation.php


这是用于将一个对象拆分为两个或多个表的工具。我需要将整个对象保留在单独的表中。 所以这不是答案。 - msangel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接