1. tabela na każdą klasę (table per concrete class)
2. tabela na każdą hierarchię klas (table per class hierarchy)
3. tabela na każdą podklasę (table per subclass)
We wszystkich przypadkach będę wykonywał metodę:
public class Main {
public static void main(String[] args) {
Session session = null;
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
session = sessionFactory.openSession();
Subcategory1 cat = new Subcategory1();
cat.setName("sub1");
cat.setSize(1);
Subcategory2 cat2 = new Subcategory2();
cat2.setName("sub2");
cat2.setVolume(2);
session.beginTransaction();
session.save(cat);
session.save(cat2);
session.flush();
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();
List<Category> cats = session.createQuery("from Subcategory1").list();
System.out.println(cats.size());
cats = session.createQuery("from Subcategory2").list();
System.out.println(cats.size());
}
}
public class Category {
Integer id;
String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Subcategory1 extends Category {
Integer id;
Integer size;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
}
public class Subcategory2 extends Category {
Integer id;
Integer volume;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getVolume() {
return volume;
}
public void setVolume(Integer volume) {
this.volume = volume;
}
}
Ad 1.
Podejście najprostsze - baza danych w ogóle nie zdaje sobie sprawy z dziedziczenia.
Tworzę DWA pliki mapowań: Subcategory1.hbm.xml, Subcategory2.hbm.xml:
<?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="main">
<class name="Subcategory1">
<id name="id" unsaved-value="null" column="category_id">
<generator class="sequence">
<param name="sequence">sub1_category_seq</param>
</generator>
</id>
<property name="name"/>
<property name="size"/>
</class>
</hibernate-mapping>
<?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="main">
<class name="Subcategory2">
<id name="id" unsaved-value="null" column="category_id">
<generator class="sequence">
<param name="sequence">sub2_category_seq</param>
</generator>
</id>
<property name="name"/>
<property name="volume"/>
</class>
</hibernate-mapping>
Stworzone zostaly dwie tabele:
CREATE TABLE subcategory1
(
category_id integer NOT NULL,
name character varying(255),
size integer,
CONSTRAINT subcategory1_pkey PRIMARY KEY (category_id)
)
CREATE TABLE subcategory2
(
category_id integer NOT NULL,
name character varying(255),
volume integer,
CONSTRAINT subcategory2_pkey PRIMARY KEY (category_id)
)
Ad2.
Podejście drugie - odwzorowanie całej hierarchii klas w jednej tabeli.
Tworzę JEDEN plik mapowań: Category.hbm.xml
<?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="main">
<class name="Category">
<id name="id" unsaved-value="null" column="category_id">
<generator class="sequence">
<param name="sequence">category_seq</param>
</generator>
</id>
<discriminator column="type" type="string" />
<property name="name" />
<subclass name="Subcategory1" discriminator-value="1">
<property name="size" />
</subclass>
<subclass name="Subcategory2" discriminator-value="2">
<property name="volume" />
</subclass>
</class>
</hibernate-mapping>
Stworzona została jedna tabela:
CREATE TABLE category
(
category_id integer NOT NULL,
"type" character varying(255) NOT NULL,
name character varying(255),
size integer,
volume integer,
CONSTRAINT category_pkey PRIMARY KEY (category_id)
)
Ważne! Podczas tworzenia pliku z mapowaniem należy pamiętać, żeby element <discriminator> znajdował się przed wszystkimi elementami <property>.
Ad 3.
Podejście trzecie polega na reprezentacji związków dziedziczenia jako powiązań relacyjnych kluczy obcych. Każda podklasa korzysta z własnej tabeli.
Tworzę trzy pliki mapowań: Category.hbm.xml, Subcategory1.hbm.xml, Subcategory2.hbm.xml
<?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="main">
<class name="Category">
<id name="id" unsaved-value="null" column="category_id">
<generator class="sequence">
<param name="sequence">category_seq</param>
</generator>
</id>
<property name="name" />
</class>
</hibernate-mapping>
<?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="main">
<joined-subclass name="Subcategory1" extends="Category">
<key column="category_id"/>
<property name="size"/>
</joined-subclass>
</hibernate-mapping>
<?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="main">
<joined-subclass name="Subcategory2" extends="Category">
<key column="category_id"/>
<property name="volume"/>
</joined-subclass>
</hibernate-mapping>
W bazie danych utworzone zostały trzy tabele:
CREATE TABLE category
(
category_id integer NOT NULL,
name character varying(255),
CONSTRAINT category_pkey PRIMARY KEY (category_id)
)
CREATE TABLE subcategory1
(
category_id integer NOT NULL,
size integer,
CONSTRAINT subcategory1_pkey PRIMARY KEY (category_id),
CONSTRAINT fk6c9080d3884719af FOREIGN KEY (category_id)
REFERENCES category (category_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
CREATE TABLE subcategory2
(
category_id integer NOT NULL,
volume integer,
CONSTRAINT subcategory2_pkey PRIMARY KEY (category_id),
CONSTRAINT fk6c9080d4884719af FOREIGN KEY (category_id)
REFERENCES category (category_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
Ten typ odwzorowania umożliwia wydawanie intuicyjnych zapytań polimorficznych:
cats = session.createQuery("from Category").list();
System.out.println(cats.size()); // "2"
Każdy wpis w tabeli subcategory1 i subcategory2 odpowiadać będzie wpisowi w tabeli category.
