hibernate inheritance mapping

sponsored links
In the domain model, in addition to association between class and class relations, and aggregation relationships, inheritance can also there is the next domain model shown, Deparment class and the Employee class as the one to many two-way association between relationship, Employee class There are two sub-categories: Skiller class and Sales category. Because Java allows only one class up to a direct parent class, Employee class, Skiller class and Sales category constitutes an inheritance tree.
hibernate inheritance mapping

In the category of object-oriented, there is the concept of multi-state, multi-state founded on the basis of inheritance. Simple to understand, polymorphism means that when a Java application variable is declared as Employee class, this variable can refer to it in fact has its own instance of the Employee class, Skiller instance of the class, it can refer to Sales class. Department class getEmps () method through the Hibernate API to retrieve from the database out of all the Employee objects. getEmps () method returns a collection of both the Employee class can contain its own instance, Skiller instance of the class, it can refer to Sales class. This query is called polymorphic queries. Database table does not exist between the inheritance, then how the inheritance relationship between domain model mapped to the relational data model as well? There are three ways hibernate mapping:

Inheritance tree root which corresponds to a table: on the relational data model, unconventional design, the table in the database by adding additional areas of the field of molecular type. In this way, relational data model can support inheritance and polymorphism.

Inheritance tree for each class corresponds to a table: in the relational data model used to represent the foreign key reference to inheritance relations.

Inheritance tree for each class corresponds to a specific table: relational data models do not support the domain model of inheritance and polymorphism.

1. Inheritance tree root which corresponds to a table employee (the entire inheritance tree a table):

employee of the table structure is as follows:

mysql> desc employee;
+------------+--------------+------+-----+-------- -+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+-------- -+----------------+
| Id | int (11) | NO | PRI | NULL | auto_increment |
| Type | int (11) | NO | | NULL | |
| Name | varchar (255) | YES | UNI | NULL | |
| Depart_id | int (11) | YES | MUL | NULL | |
| Skill | varchar (255) | YES | | NULL | |
| SaleAmount | int (11) | YES | | NULL | |
+------------+--------------+------+-----+-------- -+----------------+

Department and Employee entity class please refer to my previous article, Skiller and Sales were as follows:

package com.reiyen.hibernate.domain;

public class Skiller extends Employee {

        private String skill;
//setter And the getter method  
}
package com.reiyen.hibernate.domain;
public class Sales extends Employee {

        private int saleAmount;
//setter And the getter method  
}

Employee.hbm.xml mapping file as follows:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.reiyen.hibernate.domain">
        <class name="Employee" discriminator-value="0">
                <id name="id">
                        <generator />
                </id>
                <!--discriminator( The discriminator  ): The default type is specified as a string, here  int Type   -->
                <discriminator column="type" type="int"></discriminator>
                <property name="name" unique="true"/>
                <!-- name="department"  This name must match the properties of the Employee name in the  .  Sets the column = "depart_id", by default it will go to the  department The ID found in the  depart_id The value of the object if you want to find.  name The value of the object is equal to depart_id  , You can set the  property-ref="name" -->
                <many-to-one name="department" column="depart_id" />
                <subclass name="Skiller" discriminator-value="1">
                        <property name="skill" />
                </subclass>
                <subclass name="Sales" discriminator-value="2">
                        <property name="saleAmount" />
                </subclass>
        </class>
</hibernate-mapping>

Test class is as follows:

public class Many2One {

        public static void main(String[] args) {
                add();
                 query(1);//1
        }

        static void query(int empId) {
                Session s = null;
                Transaction tx = null;
                try {
                        s = HibernateUtil.getSession();
                        tx = s.beginTransaction();
                        Employee emp = (Employee) s.get(Employee.class, empId);//2
                        System.out.println(emp.getClass());
                        tx.commit();
                } finally {
                        if (s != null)
                                s.close();
                }
        }



        static void add() {
                Session s = null;
                Transaction tx = null;
                try {
                        Department depart = new Department();
                        depart.setName("department name");
                        
                        Employee employee1 = new Employee();
                        employee1.setDepartment(depart); //1  Object model  : The establishment of two objects of the Association   
                        employee1.setName("employee1 name1");
                        
                        Skiller employee2 = new Skiller();
                        employee2.setDepartment(depart); //2  Object model  : The establishment of two objects of the Association   
                        employee2.setName("employee2 name2");
                        employee2.setSkill("j2se");
                        
                        Sales employee3 = new Sales();
                        employee3.setDepartment(depart); //2  Object model  : The establishment of two objects of the Association   
                        employee3.setName("employee3 name3");
                        employee3.setSaleAmount(1000);
                        
                        s = HibernateUtil.getSession();
                        tx = s.beginTransaction();
                        s.save(depart);
                        s.save(employee1);
                        s.save(employee2);
                        s.save(employee3);
                        tx.commit();
                } finally {
                        if (s != null)
                                s.close();
                }
        }
}

Program runs, the console print information as follows:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id, type) values (?,?, 0)
Hibernate: insert into Employee (name, depart_id, skill, type) values (?,?,?, 1)
Hibernate: insert into Employee (name, depart_id, saleAmount, type) values (?,?,?, 2)
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart4_1_0_, employee0_.skill as skill1_0_, employee0_.saleAmount as saleAmount1_0_, employee0_.type as type1_0_ from Employee employee0_ where employee0_.id =?
class com.reiyen.hibernate.domain.Employee

employee table in the record as follows:

mysql> select * from employee;
+----+------+-----------------+-----------+------- +------------+
| Id | type | name | depart_id | skill | saleAmount |
+----+------+-----------------+-----------+------- +------------+
| 1 | 0 | employee1 name1 | 1 | NULL | NULL |
| 2 | 1 | employee2 name2 | 1 | j2se | NULL |
| 3 | 2 | employee3 name3 | 1 | NULL | 1000 |
+----+------+-----------------+-----------+------- +------------+
3 rows in set (0.00 sec)

Will test the code comments as a statement with:

query(2);

To run the console printing class as follows: class com.reiyen.hibernate.domain.Skiller

Print or query as shown above has not changed.

Based on the above changes, then test the code into the statement of 2 comments:

Employee emp = (Employee) s.get(Skiller.class, empId);

To run, then the console to print query is:

Hibernate: select skiller0_.id as id1_0_, skiller0_.name as name1_0_, skiller0_.depart_id as depart4_1_0_, skiller0_.skill as skill1_0_ from Employee skiller0_ where skiller0_.id =? And skiller0_.type = 1
class com.reiyen.hibernate.domain.Skiller

Advantages: high efficiency operation

Disadvantages: If additional sub-categories to the employee, then you must modify the table structure, add a field to the table structure; while the corresponding subclass tables in the field can not have non-empty constraint.

2. Inheritance tree for each subclass corresponds to a table (joined-subclass), table structure as follows:

hibernate inheritance mapping

Modify Employee.hbm.xml mapping file as follows:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.reiyen.hibernate.domain">
        <class name="Employee">
                <id name="id">
                        <generator />
                </id>
                <property name="name" unique="true"/>
                <!-- name="department"  This name must match the properties of the Employee name in the  .  Sets the column = "depart_id", by default it will go to the  department The ID found in the  depart_id The value of the object if you want to find.  name The value of the object is equal to depart_id  , You can set the  property-ref="name" -->
                <many-to-one name="department" column="depart_id" />
                <joined-subclass name="Skiller" table="skiller">
                 <key column="employee_id" />
                 <property name="skill" />
                </joined-subclass>
                <joined-subclass name="Sales" table="sales">
                 <key column="employee_id" />
                 <property name="saleAmount" column="sale_amount" />
                </joined-subclass>
        </class>
</hibernate-mapping>

Test class the same, but will test the code comments as a statement with:

query(2);

The console to print the information as follows:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id) values (?,?)
Hibernate: insert into Employee (name, depart_id) values (?,?)
Hibernate: insert into skiller (skill, employee_id) values (?,?)
Hibernate: insert into Employee (name, depart_id) values (?,?)
Hibernate: insert into sales (sale_amount, employee_id) values (?,?)
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_, employee0_1_.skill as skill2_0_, employee0_2_.sale_amount as sale2_3_0_, case when employee0_1_.employee_id is not null then 1 when employee0_2_.employee_id is not null then 2 when employee0_.id is not null then 0 end as clazz_0_ from Employee employee0_ left outer join skiller employee0_1_ on employee0_.id = employee0_1_.employee_id left outer join sales employee0_2_ on employee0_.id = employee0_2_.employee_id where employee0_.id =?
class com.reiyen.hibernate.domain.Skiller
The SQL statement from the print can be seen at this time, if saved is a subclass of Employee instance of an object, then, will have to keep records in two tables; if the query is sub-class object, then, is associated with a table for three query.

Based on the above changes, then test the code into the statement of 2 comments:

Employee emp = (Employee) s.get(Skiller.class, empId);

To run, then the console to print query is:

Hibernate: select skiller0_.employee_id as id1_0_, skiller0_1_.name as name1_0_, skiller0_1_.depart_id as depart3_1_0_, skiller0_.skill as skill2_0_ from skiller skiller0_ inner join Employee skiller0_1_ on skiller0_.employee_id = skiller0_1_.id where skiller0_.employee_id =?
At this point only two tables related inquiries.

Database table records as follows:

mysql> select * from employee;
+----+-----------------+-----------+
| Id | name | depart_id |
+----+-----------------+-----------+
| 1 | employee1 name1 | 1 |
| 2 | employee2 name2 | 1 |
| 3 | employee3 name3 | NULL |
+----+-----------------+-----------+
3 rows in set (0.00 sec)

mysql> select * from skiller;
+-------------+-------+
| Employee_id | skill |
+-------------+-------+
| 2 | j2se |
+-------------+-------+
1 row in set (0.00 sec)

mysql> select * from sales;
+-------------+-------------+
| Employee_id | sale_amount |
+-------------+-------------+
| 3 | 1000 |
+-------------+-------------+
1 row in set (0.00 sec)

3. Mixed with the assumption that many if Sales of property, and property Skiller little time to mixed use, "a class system in a form of succession" and "each sub-class of a table", table structure as follows:

hibernate inheritance mapping

Employee.hbm.xml mapping file as follows:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.reiyen.hibernate.domain">
        <class name="Employee" discriminator-value="0">
                <id name="id">
                        <generator />
                </id>
                <discriminator column="type" type="int" />
                <property name="name" unique="true" />
                <!-- name="department"  This name must match the properties of the Employee name in the  .  Sets the column = "depart_id", by default it will go to the  department The ID found in the  depart_id The value of the object if you want to find.  name The value of the object is equal to depart_id  , You can set the  property-ref="name" -->
                <many-to-one name="department" column="depart_id" />
<!-- If discriminator-value is not explicitly given a value,  , The value of the name attribute is consistent  , That is, to  Skiller -->          
<subclass name="Skiller" discriminator-value="1">
                        <property name="skill" />
                </subclass>
                <subclass name="Sales" discriminator-value="2">
                        <join table="sales">
                                <key column="employee_id" />
                                <property name="saleAmount" column="sale_amount" />
                        </join>
                </subclass>
        </class>
</hibernate-mapping>

At this time the same test class, but will test the code in the comment as a statement with:

query(2);

Then run the original basis of the above procedures, the console will print the following exception message:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id, type) values (?,?, 0)
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not insert: [com.reiyen.hibernate.domain.Employee]

Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'type' in 'field list'

This is because I configured in the hibernate.cfg.xml configuration file has this:

<property name="hbm2ddl.auto">create</property>

So the program is running, it will delete the database in the employee table, sales table, while the employee table have skiller table foreign key association, it can not remove the employee table, so throw the above exception. At this point you then view the database tables, as follows:

mysql> select * from employee;
+----+-----------------+-----------+
| Id | name | depart_id |
+----+-----------------+-----------+
| 1 | employee1 name1 | 1 |
| 2 | employee2 name2 | 1 |
| 3 | employee3 name3 | 1 |
+----+-----------------+-----------+
3 rows in set (0.00 sec)

mysql> select * from skiller;
+-------------+-------+
| Employee_id | skill |
+-------------+-------+
| 2 | j2se |
+-------------+-------+
1 row in set (0.00 sec)

mysql> select * from sales;
Empty set (0.00 sec)

Therefore, the data must first manually remove the skiller table, and then run the program again:

If Employee.hbm.xml profile

<subclass name="Skiller" >

Not configured discriminator-value = "1", will throw the following exceptions:

java.lang.ExceptionInInitializerError

Caused by: org.hibernate.MappingException: Could not format discriminator value to SQL string

If the discriminator-value is not explicitly given value, then the value of the property with the name remain the same, that is, Skiller, so it throws above exception!

4. Inheritance tree for each concrete class corresponds to a table (union-subclass)

Table structure is as follows:

hibernate inheritance mapping


Employee.hbm.xml mapping file as follows:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.itcast.hibernate.domain">
        <class name="Employee">
                <id name="id">
                        <generator />
                </id>
                <property name="name" unique="true" />
                <many-to-one name="department" column="depart_id" />
                <union-subclass name="Skiller" table="skiller">
                 <property name="skill" />
                </union-subclass>
                <union-subclass name="Sales" table="sales">
                 <property name="saleAmount" column="sale_amount" />
                </union-subclass>
        </class>
</hibernate-mapping>

Growth is no longer the primary key at this time are:

<generator />

If using the native form, then three will have the same id value, so that when the time under the Employee id query will be wrong. So if you configured the following native exception will be thrown (because the corresponding Employee entity class id is int, so this use hilo (high and low places) primary key generation method):

org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: com.reiyen.hibernate.domain.Skiller

Run the test program, then print the information on the console as follows:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id, id) values (?,?,?)
Hibernate: insert into skiller (name, depart_id, skill, id) values (?,?,?,?)
Hibernate: insert into sales (name, depart_id, sale_amount, id) values (?,?,?,?)
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_, employee0_.skill as skill2_0_, employee0_.sale_amount as sale1_3_0_, employee0_.clazz_ as clazz_0_ from (select id, null as sale_amount, depart_id, null as skill, name, 0 as clazz_ from Employee union select id, null as sale_amount, depart_id, skill, name, 1 as clazz_ from skiller union select id, sale_amount, depart_id, null as skill, name, 2 as clazz_ from sales) employee0_ where employee0_.id =?
class com.reiyen.hibernate.domain.Skiller

Implementation of the query, the first to use a subquery in the sub-query using the union will be the result of all three tables into a table, and then in the synthesis of a query result set.

If the Employee is an abstract class, you do not want in the data table corresponding to the corresponding data table, you can set abstract = "true". As follows:

<class name="Employee" abstract="true" >

In addition, if the inheritance relationship with interfaces, you can treat it as an abstract class.

Comparison of three mapping and selection of three ways for the convenience of explanation for the label in order to [1] the entire inheritance tree a table; [2] corresponds to a table for each subclass (joined-subclass); [4] for each specific which corresponds to a table (union-subclass).
1, complexity:

[1] simple;
[2] table between the more and the foreign key constraint;

[4] contains duplicate field;
2, the query performance:

[1] and high efficiency;
[2] need to form connections or left outer join;

[Four] if the query need to check all parent subclass table;
3, Serviceability:

[1] only a modification of a table;
[2] If a class attribute changes only modify the class corresponding to the table;

[4] If changes need to modify the properties of the parent class of all sub-categories corresponding to the table;
In summary, the choice, you can refer to the following principles:
1, sub-class of property is not a very long time, priority [1], because of its best performance.
2, sub-class of property is very large, and not very demanding on the performance, the priority consideration [2]
  • del.icio.us
  • StumbleUpon
  • Digg
  • TwitThis
  • Mixx
  • Technorati
  • Facebook
  • NewsVine
  • Reddit
  • Google
  • LinkedIn
  • YahooMyWeb

Related Posts of hibernate inheritance mapping

  • Great Design

    Understand the principle with the practice, details the relationship between thought, we'll go have selectively study the details, we must work on the details because the details are important to you to use the technical details of implementation ...

  • hibernate study of the second

    Persistence of three main points: 1, a statement for persistent fields accessors (accessors) and whether the variable signs (mutators) Property statement is not necessarily required for the public's. Hibernate can be default, protected or private ...

  • Hibernate in the inverse and cascade

    First of all, to quote another blog saying: 1.cascade ="..."? cascade is not a property of many-to-many relationship must have it just so that we insert or delete at the time like some more convenient, as long as the source of the cascade insert

  • Building Scalable java EE application (2)

    When the number of concurrent users marked the beginning of growth, you may be dissatisfied with a single machine can provide the performance, or because of a single JVM instance gc restrictions, you can not expand your java application, in such circumsta

  • Choose Hibernate or iBATIS has its reasons

    Hibernate features: Hibernate powerful database has nothing to do with good, O / R mapping ability, and if you are very proficient in Hibernate, but also for Hibernate to conduct an appropriate package, then your project will be the entire persistence lay

  • How the primary key agent-hibernate

    Existing Table A, B Statement: A, B field id-based keys. A: [id, name] B: [id, Aid, title] B and A's set up a many-to-one relationship because of A, B two tables are the primary key id field so add B when Hibernate will automatically retrieve id ...

  • FLEX: integrating Spring + Hibernate

    Before a friend also wanted to study development of FLEX. Asked me to help him to be a small sample. Spent a weekend time, to integrate a sampleproject. Client: FLEX Server: Spring2.5 + Hibernate3.2 + Hibernate-annotations3.3.1 + MySQL5 FDS: BlazeDS3 IDE:

  • Hibernate Mapping Types

    Hibernate mapping types divided into two categories: built-in mapping types and mapping types of customers. Built-in mapping types is responsible for some common Java types are mapped to the corresponding SQL type; In addition, Hibernate also allows users

  • Hibernate configuration parameters hibernate.hbm2ddl.auto

    Hibernate in the configuration file: <properties> <property name="hibernate.hbm2ddl.auto" value="create" /> </ properties> Parameter Description: validate load hibernate, the authentication to create a database t ...

  • Hibernate.cfg.xml configuration file (including the primary key generation strategy Introduction)

    Hibernate.cfg.xml configuration file: <? xml version = "1.0" encoding = "utf-8"?> <! DOCTYPE hibernate-configuration PUBLIC "- / / Hibernate / Hibernate Configuration DTD / / EN" "hibernate-configuration-2.0.dtd

blog comments powered by Disqus
Recent
Recent Entries
Tag Cloud
Random Entries