Hibernate Tutorial
Core Hibernate
Hibernate Mapping
Hibernate Annotations
Hibernate with Spring Framework
Hibernate with Database
Hibernate Log4j
Inheritance Mapping
Using the "Table Per Hierarchy" strategy with Hibernate means storing all entities of an inheritance hierarchy in a single table, differentiated by a discriminator column. This tutorial will guide you on how to map this strategy using XML configuration.
Ensure you have a Hibernate project ready with the necessary dependencies and configuration files.
Base Class (Vehicle):
This class will be our parent class.
public abstract class Vehicle { private Long id; private String manufacturer; // Getters, setters, constructors... }
Concrete Subclasses (Car and Bike):
public class Car extends Vehicle { private int numberOfSeats; // Getters, setters, constructors... } public class Bike extends Vehicle { private int saddleHeight; // Getters, setters, constructors... }
Vehicle.hbm.xml:
<hibernate-mapping> <class name="Vehicle" table="VEHICLE" discriminator-value="none" abstract="true"> <id name="id" column="ID"> <generator class="native"/> </id> <discriminator column="VEHICLE_TYPE" type="string"/> <property name="manufacturer" column="MANUFACTURER"/> <!-- Subclass mappings --> <subclass name="Car" discriminator-value="Car"> <property name="numberOfSeats" column="NUMBER_OF_SEATS"/> </subclass> <subclass name="Bike" discriminator-value="Bike"> <property name="saddleHeight" column="SADDLE_HEIGHT"/> </subclass> </class> </hibernate-mapping>
In the above XML:
discriminator
tag is used to specify the discriminator column.subclass
tag is used to define the properties and discriminator values of each subclass.Ensure that this XML file is appropriately registered in your Hibernate configuration file (hibernate.cfg.xml
).
When you create and save an instance of Car
:
Car car = new Car(); car.setManufacturer("Toyota"); car.setNumberOfSeats(4); session.save(car);
Hibernate will generate an insert statement for the VEHICLE
table with a VEHICLE_TYPE
of "Car".
When you fetch an entity, Hibernate will look at the discriminator column to determine which entity type to instantiate.
Vehicle retrievedVehicle = session.get(Vehicle.class, vehicleId);
If the VEHICLE_TYPE
for the given ID is "Car", retrievedVehicle
will actually be an instance of Car
.
Benefits:
Drawbacks:
"Table Per Hierarchy" is a compact way of mapping an inheritance hierarchy to a relational database when using Hibernate's XML configuration. While it's efficient for querying, care should be taken when designing the hierarchy to avoid a table with many nullable columns. Always choose the inheritance strategy based on your application's requirements.
Hibernate table per hierarchy XML mapping example:
<class>
elements for each class and <discriminator>
for the discriminator column.<!-- Animal.hbm.xml --> <class name="com.example.Animal" table="animal"> <id name="id" type="long"> <generator class="increment"/> </id> <discriminator column="animal_type" type="string"/> <!-- Common fields and mappings --> </class>
<!-- Cat.hbm.xml --> <subclass name="com.example.Cat" extends="com.example.Animal" discriminator-value="CAT"> <!-- Cat-specific fields and mappings --> </subclass>
<!-- Dog.hbm.xml --> <subclass name="com.example.Dog" extends="com.example.Animal" discriminator-value="DOG"> <!-- Dog-specific fields and mappings --> </subclass>
Configuring table per hierarchy inheritance in Hibernate using XML:
<class>
and <subclass>
elements in the same mapping file.<!-- Animal.hbm.xml --> <class name="com.example.Animal" table="animal"> <id name="id" type="long"> <generator class="increment"/> </id> <discriminator column="animal_type" type="string"/> <!-- Common fields and mappings --> </class>
<!-- Cat.hbm.xml --> <subclass name="com.example.Cat" extends="com.example.Animal" discriminator-value="CAT"> <!-- Cat-specific fields and mappings --> </subclass>
<!-- Dog.hbm.xml --> <subclass name="com.example.Dog" extends="com.example.Animal" discriminator-value="DOG"> <!-- Dog-specific fields and mappings --> </subclass>
Mapping hierarchical classes with Hibernate XML mapping:
<class>
elements for the superclass and <subclass>
elements for each subclass.<!-- Animal.hbm.xml --> <class name="com.example.Animal" table="animal"> <id name="id" type="long"> <generator class="increment"/> </id> <discriminator column="animal_type" type="string"/> <!-- Common fields and mappings --> </class>
<!-- Cat.hbm.xml --> <subclass name="com.example.Cat" extends="com.example.Animal" discriminator-value="CAT"> <!-- Cat-specific fields and mappings --> </subclass>
<!-- Dog.hbm.xml --> <subclass name="com.example.Dog" extends="com.example.Animal" discriminator-value="DOG"> <!-- Dog-specific fields and mappings --> </subclass>
Table per hierarchy vs table per concrete class in Hibernate XML:
<class>
element for the entire hierarchy, while table per concrete class uses separate <class>
elements for each concrete class.<!-- Table per hierarchy --> <class name="com.example.Animal" table="animal"> <!-- Common fields and mappings --> </class>
<!-- Table per concrete class --> <class name="com.example.Cat" table="cat"> <!-- Cat-specific fields and mappings --> </class>
<!-- Table per concrete class --> <class name="com.example.Dog" table="dog"> <!-- Dog-specific fields and mappings --> </class>
Inheritance strategies with XML mapping in Hibernate:
<subclass>
, <joined-subclass>
, or <union-subclass>
elements.<!-- Animal.hbm.xml --> <class name="com.example.Animal" table="animal"> <!-- Common fields and mappings --> </class>
<!-- Cat.hbm.xml --> <subclass name="com.example.Cat" extends="com.example.Animal" discriminator-value="CAT"> <!-- Cat-specific fields and mappings --> </subclass>
<!-- Dog.hbm.xml --> <subclass name="com.example.Dog" extends="com.example.Animal" discriminator-value="DOG"> <!-- Dog-specific fields and mappings --> </subclass>
Hibernate XML mapping for @Inheritance annotation in table per hierarchy:
<class>
and <subclass>
elements in Hibernate XML correspond to the @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
annotation in table per hierarchy.<!-- Animal.hbm.xml --> <class name="com.example.Animal" table="animal"> <discriminator column="animal_type" type="string"/> <!-- Common fields and mappings --> </class>
<!-- Cat.hbm.xml --> <subclass name="com.example.Cat" extends="com.example.Animal" discriminator-value="CAT"> <!-- Cat-specific fields and mappings --> </subclass>
<!-- Dog.hbm.xml --> <subclass name="com.example.Dog" extends="com.example.Animal" discriminator-value="DOG"> <!-- Dog-specific fields and mappings --> </subclass>
Handling associations in table per hierarchy mapping with XML:
<!-- Animal.hbm.xml --> <class name="com.example.Animal" table="animal"> <discriminator column="animal_type" type="string"/> <!-- Common fields and mappings --> </class>
<!-- Person.hbm.xml --> <class name="com.example.Person" table="person"> <!-- Person-specific fields and mappings --> </class>
<!-- Cat.hbm.xml --> <subclass name="com.example.Cat" extends="com.example.Animal" discriminator-value="CAT"> <!-- Cat-specific fields and mappings --> <many-to-one name="owner" class="com.example.Person" column="owner_id"/> </subclass>
HQL queries for table per hierarchy inheritance in Hibernate XML:
String hql = "FROM Animal WHERE color = :color"; Query query = session.createQuery(hql); query.setParameter("color", "black"); List<Animal> blackAnimals = query.list();
Replace this code with the relevant XML configuration.