Hibernate,映射继承的字段

时间:2013-11-29 17:37:25

标签: java hibernate

假设我有以下类层次结构:

class Person {
    String name;
    int age;
}
class DatabasePerson extends Person {
    int databaseId;
}

现在我想映射DatabasePerson,请注意我不想告诉hibernate存在Person类,hibernate应该只知道关于DatabasePerson类的xml或注释映射。是否可以通过采用上述条件的hibernate映射年龄和名称字段?换句话说,我想用Hibernate映射DatabasePerson类,而hibernate不应该知道Person类。在xml中我会像这样(伪代码):

<hibernate class="DatabasePerson">
     <field name="id"/>
     <field name="name"/>
     <field name="age"/>
</hibernate>

这样做的原因是保持单一责任原则。我不想将databaseId字段放入Person类,因为person类不应该知道它是持久的。我不想在Person类中包含任何hibernate注释,因为我有纯粹的实体逻辑,我不想在那里导入任何与数据库相关的东西,比如hibernate。我想在DatabasePerson类中做的所有映射,这是我想放置额外的databaseId字段的地方,写hibernate注释(或者xml,我现在不知道,我想推迟这个决定)。换句话说,我们希望将数据库相关的东西和我们的应用程序逻辑保存在不同的类中。

编辑: 我可以使用这样的东西吗?:

<class name="Person" table="PERSON" discriminator-value="P">


    <discriminator column="DISCRIMINATOR" type="string" />

    <property name="name" />
    <property name="age"  />

    <subclass name="DatabasePerson" extends="Person" >
        <id name="databaseId" column="ID">
            <generator class="native" />
        </id>

    </subclass>
</class>

请注意,数据库ID位于此xml中的DatabasePerson范围内。

编辑: 这个xml映射是否与注释“映射的超类”相对应?我想我更喜欢使用xml而不是注释,所以我的问题是如何在xml中使用@MappedSuperclass:

<class name="Person" table="PERSON" discriminator-value="P">
    <id name="databaseId" column="PERSON_ID">
        <generator class="native" />
    </id>

    <discriminator column="DISCRIMINATOR" type="string" />

    <subclass name="DatabasePerson" extends="Person" discriminator-value="E">
            <property name="name" column="name" />
            <property name="age" type="int" column="age" />
    </subclass>
</class>

3 个答案:

答案 0 :(得分:3)

我认为你可以使用MappedSupperclass注释或singel表继承策略只使用数据库中的一个表。两种情况下JPA / Hibernate都知道Person类,但它没有为这个类创建表。 (当然可以使用XML调整而不是注释,但我只使用了注释。)

@MappedSuperclass注释。

如果您只想使用一个包含两个java类中所有列的数据库表(DatabasePerson),那么您可以使用以下注释:

@MappedSuperclass
class Person {
    String name;
    int age;
}

@Entity
class DatabasePerson extends Person {
    int databaseId;
}

我认为在这种情况下更好的改变Person类来抽象类。


InheritanceType.SINGLE_TABLE

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="yourtype",
    discriminatorType=DiscriminatorType.STRING
)
class DatabasePerson{
    int databaseId;
}


@Entity
@DiscriminatorValue("P")
class Person extends DatabasePerson{
        String name;
        int age;
    }

这个startegy使用鉴别器列并且只保留一个表。

答案 1 :(得分:1)

试试吧

<hibernate-mapping package="Yourpackage">

    <class name="Person" table="PERSON" >
        <id name="databaseId" column="ID">
            <generator class="native" />
        </id>

        <discriminator column="DISCRIMINATOR" type="string" />

        <property name="name" />
        <property name="age"  />

        <subclass name="DatabasePerson" extends="Person" >
                <property name="databaseId" column="database_Id" />

        </subclass>
    </class>
</hibernate-mapping>

这可能是同样的例子

http://viralpatel.net/blogs/hibernate-inheritence-table-per-hierarchy-mapping/

答案 2 :(得分:-1)

Hibernate XML配置与它完美匹配,我在其中一个项目中广泛使用它。我的情况如下,可能听起来不同,但它和你的情况一样。

class Entity {
    private int _id;
    public int getId() { return _id; }
    public void setId(int id) { _id = id; }
}

class User extends Entity {
    private String _email;
    public String getEmail() { return _email; }
    public void setEmail(String email) { _email = email; }
}

我的目的是让User(以及我所有其他实体)继承id,因为你试图让DatabasePerson继承Person.name和age。

然后,在为User配置映射时,我编写了以下XML文件。

<hibernate-mapping>
    <class name="User" table="User">
        <id name="id" type="int" column="id">
            <generator class="identity"/>
        </id>
        <property name="email" type="string">
             <column name="email" sql-type="varchar(255)"/>
        </property>

        .....
    </class>
</hibernate-mapping>

正如您所看到的,上述XML文件中没有任何对Entity的引用,在您的情况下转换为:您的XML文件仅处理DatabasePerson,因为Person根本不存在; Hibernate将使用Java内省从Entity中检索id,作为您案例的Person.name。

我唯一不确定的是,您的Person.name和Person.age字段是可以保留为受保护还是应该提升为公共字段。无论哪种方式,您都可以将它们保留为受保护的(并最终)提供方法DatabasePerson.getName()和DatabasePerson.setName()(无需在Person级别提供这些getter / setter)。

作为旁注,在其他答案中,您被建议使用hibernate“subclass”或“MappedSuperclass”。这些不是必需的,在你的情况下它们的使用在语义上是错误的:它们应该在你有一个数据库实体扩展另一个数据库实体时使用,但在你的情况下,DatabasePerson是一个扩展POJO类(Person)的数据库实体。