简体   繁体   中英

Hibernate, mapping inherited fields

Lets say I have a following class hierarchy:

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

Now I would like to map the DatabasePerson, please notice that I don't would like to tell hibernate that there exist a Person class, hibernate should only know about the DatabasePerson class while xml or annotation mapping. Is it possible to map the age and name fields with hibernate adopting the above mentioned condition ? In other words I would like to map the DatabasePerson class with hibernate and hibernate should not know about the Person class. In xml I would make it like this (Pseudo-code):

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

The reason for doing that is to keep the single responsibility principle. I don't would like to put the databaseId field into the Person class, because the person class shouldn't know that it is persisted. I don't would like to include any hibernate annotations into Person class because I have there pure entity logic and I don't want do import there any database related stuff like hibernate. All mappings I would like to do in the DatabasePerson class, this is the place where I would like to put the additional databaseId field, write hibernate annotations (or maybe xml, I don't know it right now, I would like to postpone this decision). I other words we want to keep the database related stuff and our application logic in separate classes.

Edit: Can I use something like this?:

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

Notice that the database id is in the DatabasePerson scope in this xml.

Edit: Is this xml mapping respective to the annotation 'mapped superclass' ? I think I preffer to use xml instead of annotations so my question is how to use @MappedSuperclass in xml:

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

I think can you use MappedSupperclass annotation or singel table inheritance strategy for use only one table in database. Both case the JPA/Hibernate know about Person class, but It doesn't create table for this class. (Of course could you use XML adjustment instead of annotations, but I've used only annotations.)

@MappedSuperclass annotation.

If you want to use only one database table (DatabasePerson) which included all columns from both java classes, than you could use following annotations:

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

@Entity
class DatabasePerson extends Person {
    int databaseId;
}

I think in this case is better change Person class to abstract class.


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;
    }

This startegy use discriminator column and persist only one table.

Try it

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

May be possible same example here

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

Hibernate XML configuration deals perfectly with it and I've used it extensively in one of the projects I worked on. My scenario was the following, which might sound different but it is just the same as yours.

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; }
}

My intention here was to have User (and all my others entities) to inherit the id, as you're trying to have DatabasePerson inheriting Person.name and age.

Then, when configuring the mapping for User I've written the following XML file.

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

As you can see, there is no any single reference to Entity from the above XML file, which in your case translates to: your XML file only deals with DatabasePerson as Person wouldn't exist at all; Hibernate will use Java introspection to retrieve id from Entity, as Person.name for your case.

The only thing I'm not sure, is whether your Person.name and Person.age field can be left as protected or should be promoted to public. Either way, you can leave them as protected and (eventually) provide the method DatabasePerson.getName() and DatabasePerson.setName() (no need to provide these getter/setter at Person level).

As a side note, in other answers you have been suggested to use hibernate "subclass" or "MappedSuperclass". These are not required, and they usage is even semantically wrong in your case: They are supposed to be used when you have a DB entity extending another DB entity, but in your case DatabasePerson is a DB Entity extending a POJO class (Person).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM