Hibernate继承和具有相同类的多个表

时间:2011-07-29 12:06:23

标签: java hibernate jpa

我对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)可以用注释写吗?我无法理解如何定义Ref1和Ref2类而不实际为它们创建POJO类。 (d)我可以使用超过1级的继承吗?例如,我想为我的所有具体表使用抽象超类,它们涵盖了它们共有的审计字段? 假设类Ref扩展了一个抽象的AuditTable类,包括Java和Hibernate映射。

3 个答案:

答案 0 :(得分: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参考实现(使用注释)

  

(C-a)我无法理解如何定义Ref1和Ref2类   实际上为他们创建了一个POJO类?

如果不创建Ref1和Ref2 pojo类,则无法完成。

  

(d)我可以使用超过1级的继承吗?我想,例如,   对我所有的具体表使用抽象超类来覆盖   他们都有共同的审计领域?让我们说课程参考延伸   一个抽象的AuditTable

带注释的示例

基类Ref.java

@MappedSuperclass
public abstract class Ref {

    String value;

}

Class Ref1.java

@Entity
public class Ref1 extends Ref {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
}

Class Ref2.java

@Entity
public class Ref2 extends Ref {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
}

Class 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.

要使用hibernate maping文件,您需要删除所有注释,使用下面的映射。

当使用映射文件时,不会映射抽象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>

答案 1 :(得分:0)

只有一个问题....如果你使用同一个类访问几个不同的表... 哪个表将存储您保存的新实例? Hibernate将如何知道?

AFAIK,这是不可能的。

答案 2 :(得分:0)

这些快捷方式即使可以使用,也常常会导致继承您代码的开发人员最终混淆的道路。在你提出问题之前&#34;可以做到&#34;,问问&#34;它应该完成&#34;。

在路上思考:更高效率和更高效率是否更好?在开发时通过创建更少的类并使用一些有些模糊的功能,或者更好地制作单独的类并使事情更易于理解。此外,你可能会陷入困境,因为这个特定的功能可能会导致意想不到的后果,经典&#34;为什么它 &#34;情况。

我继承了许多应用程序,前几代开发人员希望在&#34; cool&#34;或者&#34;优雅&#34;方式并最终导致更多的混乱,而不是他们保持具体和简单的事情。

只需创建单独的类。