Данная глава демонстрирует несколько мэппингов для более сложных ассоциаций.
Следующая модель взаимоотношений между работодателем, класс Employer и работником Employee использует реальный класс-сущность (entity class) Employment, для представления ассоциации. Это сделано по причине того, что возможно более одного зарегистрированного периода работы одного и того же служащего на одного и того же работодателя. Для представления денежных значений и имен слежащих, используются компоненты (components), MonetoryAmmounts и Name соответсвенно.
Вот возможный мэппинг для данной модели:
<hibernate-mapping> <class name="Employer" table="employers"> <id name="id"> <generator class="sequence"> <param name="sequence">employer_id_seq</param> </generator> </id> <property name="name"/> </class> <class name="Employment" table="employment_periods"> <id name="id"> <generator class="sequence"> <param name="sequence">employment_id_seq</param> </generator> </id> <property name="startDate" column="start_date"/> <property name="endDate" column="end_date"/> <component name="hourlyRate" class="MonetoryAmount"> <property name="amount"> <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/> </property> <property name="currency" length="12"/> </component> <many-to-one name="employer" column="employer_id" not-null="true"/> <many-to-one name="employee" column="employee_id" not-null="true"/> </class> <class name="Employee" table="employees"> <id name="id"> <generator class="sequence"> <param name="sequence">employee_id_seq</param> </generator> </id> <property name="taxfileNumber"/> <component name="name" class="Name"> <property name="firstName"/> <property name="initial"/> <property name="lastName"/> </component> </class> </hibernate-mapping>
А вот схема таблиц, сгенерированная для данного мэппинга, при помощи инструмента SchemaExport:
create table employers ( id BIGINT not null, name VARCHAR(255), primary key (id) ) create table employment_periods ( id BIGINT not null, hourly_rate NUMERIC(12, 2), currency VARCHAR(12), employee_id BIGINT not null, employer_id BIGINT not null, end_date TIMESTAMP, start_date TIMESTAMP, primary key (id) ) create table employees ( id BIGINT not null, firstName VARCHAR(255), initial CHAR(1), lastName VARCHAR(255), taxfileNumber VARCHAR(255), primary key (id) ) alter table employment_periods add constraint employment_periodsFK0 foreign key (employer_id) references employers alter table employment_periods add constraint employment_periodsFK1 foreign key (employee_id) references employees create sequence employee_id_seq create sequence employment_id_seq create sequence employer_id_seq
Рассмотрим следующую модель взаимодействий между работой, класс Work инициатором, класс Author и человеком, Person. Мы изображаем взаимодействие между классами Work и Author, как отношение многие-ко-многим (many-to-many). Для отображения взаимотношений между сущностями Author и Person, мы используем ассоциацию один-к-одному (one-to-one). Другой вариант, это использование наследования следующим образом: класс Author расширяет (extend) Person.
Следующий мэппинг, правильно отображет данные отношения между классами:
<hibernate-mapping> <class name="Work" table="works" discriminator-value="W"> <id name="id" column="id"> <generator class="native"/> </id> <discriminator column="type" type="character"/> <property name="title"/> <set name="authors" table="author_work" lazy="true"> <key> <column name="work_id" not-null="true"/> </key> <many-to-many class="Author"> <column name="author_id" not-null="true"/> </many-to-many> </set> <subclass name="Book" discriminator-value="B"> <property name="text"/> </subclass> <subclass name="Song" discriminator-value="S"> <property name="tempo"/> <property name="genre"/> </subclass> </class> <class name="Author" table="authors"> <id name="id" column="id"> <!-- The Author must have the same identifier as the Person --> <generator class="assigned"/> </id> <property name="alias"/> <one-to-one name="person" constrained="true"/> <set name="works" table="author_work" inverse="true" lazy="true"> <key column="author_id"/> <many-to-many class="Work" column="work_id"/> </set> </class> <class name="Person" table="persons"> <id name="id" column="id"> <generator class="native"/> </id> <property name="name"/> </class> </hibernate-mapping>
В данном мэппинге используется четыре таблицы. Таблицы works, authors и persons содержат информацию о работе, инициаторе и человеке соответсвенно. Таблица author_work, является таблицей-ассоциаций (association table), связывающей инициаторов с работами. Вот схема таблиц, сгенерированная при помощи SchemaExport:
create table works ( id BIGINT not null generated by default as identity, tempo FLOAT, genre VARCHAR(255), text INTEGER, title VARCHAR(255), type CHAR(1) not null, primary key (id) ) create table author_work ( author_id BIGINT not null, work_id BIGINT not null, primary key (work_id, author_id) ) create table authors ( id BIGINT not null generated by default as identity, alias VARCHAR(255), primary key (id) ) create table persons ( id BIGINT not null generated by default as identity, name VARCHAR(255), primary key (id) ) alter table authors add constraint authorsFK0 foreign key (id) references persons alter table author_work add constraint author_workFK0 foreign key (author_id) references authors alter table author_work add constraint author_workFK1 foreign key (work_id) references works
Теперь рассмотрим модель взаимоотношений между клиентом, класс Customer; заказом Order; и классами пункт заказа LineItem, и товар Product. Отоношение между классами Customer и Order явлется отношением один-ко-многим (one-to-many); но как мы должны отобразить отношение Order / LineItem / Product? Мы выбрали вариант мэппига с использованием LineItem, как класса-ассоциации (association class), для представления ассоциации многие-ко-многим (many-to-many) между сущностями Order и Product. В Hibernate такой мэппинг называется мэппингом с использованием составного элемента (composite element), в данном случае LineItem -- класс составного элемента.
Мэппинг:
<hibernate-mapping> <class name="Customer" table="customers"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="orders" inverse="true" lazy="true"> <key column="customer_id"/> <one-to-many class="Order"/> </set> </class> <class name="Order" table="orders"> <id name="id"> <generator class="native"/> </id> <property name="date"/> <many-to-one name="customer" column="customer_id"/> <list name="lineItems" table="line_items" lazy="true"> <key column="order_id"/> <index column="line_number"/> <composite-element class="LineItem"> <property name="quantity"/> <many-to-one name="product" column="product_id"/> </composite-element> </list> </class> <class name="Product" table="products"> <id name="id"> <generator class="native"/> </id> <property name="serialNumber"/> </class> </hibernate-mapping>
Таблицы customers, orders, line_items и products, содержат информацию о клиенте, заказе, элементах заказа и товаре соответсвенно. Таблица line_items, также выполняет функции связывающей таблицы для заказов и товаров.
create table customers ( id BIGINT not null generated by default as identity, name VARCHAR(255), primary key (id) ) create table orders ( id BIGINT not null generated by default as identity, customer_id BIGINT, date TIMESTAMP, primary key (id) ) create table line_items ( line_number INTEGER not null, order_id BIGINT not null, product_id BIGINT, quantity INTEGER, primary key (order_id, line_number) ) create table products ( id BIGINT not null generated by default as identity, serialNumber VARCHAR(255), primary key (id) ) alter table orders add constraint ordersFK0 foreign key (customer_id) references customers alter table line_items add constraint line_itemsFK0 foreign key (product_id) references products alter table line_items add constraint line_itemsFK1 foreign key (order_id) references orders