Hibernate继承和具有相同类的多个表
Posted
技术标签:
【中文标题】Hibernate继承和具有相同类的多个表【英文标题】:Hibernate inheritance and multiple tables with same class 【发布时间】:2011-07-29 12:06:22 【问题描述】:我对 Hibernate 还是很陌生。在我的情况下,我有一个具体的表,其中包含与许多其他表的连接 ID 的记录——所有表都具有相同的结构。 我想要实现的是得到类似
SELECT *
FROM main_records mr, ref1 r1, ref2 r2
WHERE r1.id = mr.id_ref1
AND r2.id = mr.id_ref2;
主要思想是为所有连接引用重用该类。
SQL
CREATE TABLE main_records
(
id integer NOT NULL,
id_ref1 integer NOT NULL,
id_ref2 integer NOT NULL
)
CREATE TABLE ref1
(
id integer NOT NULL,
value character varying
)
CREATE TABLE ref2
(
id integer NOT NULL,
value character varying
)
我已经设置了基础 POJO 类
JAVA 类
public class MainRecord
private Integer id;
private Ref ref1;
private Ref ref2;
...
// getters and setters
public class Ref
private Integer id;
private String value;
...
// getters and setters
我的想法是通过以下方式定义 Hibernate 映射:
定义一个抽象超类
<hibernate-mapping package="test">
<class abstract="true" name="Ref">
<id name="id" type="java.lang.Integer" column="ID">
<generator class="native" />
</id>
<property name="value" type="java.lang.String" column="VALUE" />
</class>
</hibernate-mapping>
映射主实体,扩展超类但使用单独的表
<hibernate-mapping package="test">
<union-subclass name="Ref1" table="REF1" extends="Ref" />
<union-subclass name="Ref2" table="REF2" extends="Ref" />
<class name="MainRecord" table="MAIN_RECORDS">
<id name="id" column="ID" type="java.lang.Integer" />
<many-to-one name="ref1" class="Ref1" column="ID_REF1" fetch="join" unique="true" />
<many-to-one name="ref2" class="Ref2" column="ID_REF2" fetch="join" unique="true" />
</union-subclass>
</class>
</hibernate-mapping>
我确实在配置中手动包含映射文件,加载似乎还可以,但随后出现错误,没有任何详细说明:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.apache.cxf.transport.servlet.ServletTransportFactory' defined in class path resource [META-INF/cxf/cxf-servlet.xml]: Error setting property values;
nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (2) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'bus' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/spring/database.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
PropertyAccessException 2: org.springframework.beans.MethodInvocationException: Property 'transportIds' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/spring/database.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1361)
该系统混合了 Spring 2.5、Hibernate 3.2、Cxf 2.3.4、Javassist 3.11,
我的问题是:
(a) 这是正确的方法吗?
(b) 我一介绍就出错了
<union-subclass name="Ref1" table="REF1" extends="Ref" />
<union-subclass name="Ref2" table="REF2" extends="Ref" />
所以我想这不是最好的方法吗?
(c) 可以用注解写吗?如果不为它们实际创建 POJO 类,我无法理解如何定义 Ref1 和 Ref2 类。 (d) 我可以使用 1 级以上的继承吗?例如,我想为我所有的具体表使用一个抽象超类,它涵盖了它们共有的审计字段? 假设类 Ref 在 Java 和 Hibernate 映射中扩展了一个抽象的 AuditTable 类。
【问题讨论】:
【参考方案1】:如果我正确理解了这个问题,您有一个主记录表,其中包含多个外键到许多彼此具有相同列的表?
(a) 这是正确的方法吗?
不,您正在尝试通过使用 Table per class 策略来进行继承,我认为这里不适合使用,因为您对每个类型对象都有一个引用(在您的情况下是字段 Ref1 和字段 Ref2)。 适合使用继承的用例是,如果您在 MasterRecord 对象中与 Ref 有一个多态关联
与 Ref 的多态关联示例
public class MasterRecord
Long id;
Ref anyObjectRef1OrRef2; <-- Polymorphic association
关联 anyObjectRef1OrRef2
将与 MasterRecord 映射中的 <any ... />
元素进行映射。它需要两列,第一列是 className,另一列是 foreignKey
(b)我一介绍
<union-subclass
就会出现错误...所以我想这不是最好的方法吗?
你应该做的是从超类继承属性(这个超类没有特定的表)
(C)可以用注解写吗?
是的,使用@MappedSuperclass 注解。Hibernate 参考实现(使用注解)
Mapping inheritance 见第 2.2.4.4 节。从超类继承属性(C-a)如果没有,我无法理解如何定义 Ref1 和 Ref2 类 实际上为他们创建了一个 POJO 类?
不创建 Ref1 和 Ref2 pojo 类就无法完成。
Section 2.2.4.4. Inherit properties from superclasses(d)我可以使用多于 1 级的继承吗?例如,我想 为我所有的具体表使用一个抽象超类,涵盖 他们都有共同的审计领域?假设类 Ref 扩展 一个抽象的 AuditTable
带注释的示例
基类引用.java
@MappedSuperclass
public abstract class Ref
String value;
类 Ref1.java
@Entity
public class Ref1 extends Ref
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
类 Ref2.java
@Entity
public class Ref2 extends Ref
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
类 MainRecord.java
@Entity
public class MainRecord
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@ManyToOne(cascade=CascadeType.ALL, targetEntity=Ref1.class)
Ref ref1;
@ManyToOne(cascade=CascadeType.ALL, targetEntity=Ref2.class)
Ref ref2;
如下创建并保存实体
..begin transaction
MainRecord mainRecord = new MainRecord();
Ref1 ref1 = new Ref1();
ref1.setValue("tettset");
Ref2 ref2 = new Ref2();
ref2.setValue("tettset");
mainRecord.setRef2(ref2);
mainRecord.setRef1(ref1);
entitymanager.persist(mainRecord);
..commit transaction.
要使用休眠映射文件,您需要使用下面的映射删除所有注释。
并不是说在使用映射文件时,抽象Ref.java
超类没有被映射,超类的所有属性都在每个子映射文件中。
<class name="MainRecord" table="MAIN_RECORDS">
<id name="id" column="uid" type="long">
<generator class="identity"/>
</id>
<many-to-one name="ref1" class="Ref1" column="ID_REF1" fetch="join" unique="true" cascade="all" />
<many-to-one name="ref2" class="Ref2" column="ID_REF2" fetch="join" unique="true" cascade="all" />
</class>
<class name="Ref1" table="REF1">
<id name="id" column="uid" type="long">
<generator class="identity"/>
</id>
<property name="value" type="java.lang.String" column="VALUE" />
</class>
<class name="Ref2" table="REF2">
<id name="id" column="uid" type="long">
<generator class="identity"/>
</id>
<property name="value" type="java.lang.String" column="VALUE" />
</class>
【讨论】:
感谢您的示例,进入这个方向机器人遇到了新的麻烦。更多细节在这里***.com/questions/7105832/…【参考方案2】:只有一个问题....如果您使用同一个类来访问多个不同的表... 您保存的新实例将存储到哪个表? Hibernate 怎么知道?
AFAIK,这是不可能的。
【讨论】:
不应该通过 Ref1 和 Ref2 类解决吗?他们定义了正确的表格。类 Ref 仅用于字段映射。【参考方案3】:诸如此类的快捷方式,即使它们可以正常工作,也常常会导致继承您的代码的开发人员最终感到困惑。在问“可以做到”之前,先问“应该做到”。
想一想:是在开发时通过创建更少的类并使用一些晦涩的功能来提高“效率”,还是只制作单独的类并让事情更容易理解更好。此外,您可能会陷入困境,因为此特定功能可能会导致意想不到的后果,即经典的“为什么要这样做”的情况。
我继承了许多应用程序,前几代开发人员希望以“酷”或“优雅”的方式做事,结果导致比让事情具体和简单更混乱。
只需创建单独的类。
【讨论】:
以上是关于Hibernate继承和具有相同类的多个表的主要内容,如果未能解决你的问题,请参考以下文章