hibernate-orm/reference/zh-cn/modules/example_mappings.xml

610 lines
18 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<chapter id="example-mappings">
<title>示例:复杂映射实例</title>
<para>
本章展示了一些较为复杂的关系映射。
</para>
<sect1 id="example-mappings-emp">
<title>Employer雇主)/Employee(雇员)</title>
<para>
下面关于<literal>Employer</literal><literal>Employee</literal>的关系模型使用了一个真实的实体类
(<literal>Employment</literal>)来表述,这是因为对于相同的雇员和雇主可能会有多个雇佣时间段。
对于金额和雇员姓名用Components建模。
</para>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
</imageobject>
</mediaobject>
<para>
映射文件可能是这样:
</para>
<programlisting><![CDATA[<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="MonetaryAmount">
<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>]]></programlisting>
<para>
<literal>SchemaExport</literal>生成表结构。
</para>
<programlisting><![CDATA[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]]></programlisting>
</sect1>
<sect1 id="example-mappings-authorwork">
<title>Author(作家)/Work(作品)</title>
<para>
考虑下面的<literal>Work</literal>,<literal>Author</literal><literal>Person</literal>模型的关系。
我们用多对多关系来描述<literal>Work</literal><literal>Author</literal>
用一对一关系来描述<literal>Author</literal><literal>Person</literal>
另一种可能性是<literal>Author</literal>继承<literal>Person</literal>
</para>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
</imageobject>
</mediaobject>
<para>
下面的映射文件正确的描述了这些关系:
</para>
<programlisting><![CDATA[<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">
<key column name="work_id"/>
<many-to-many class="Author" column name="author_id"/>
</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">
<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>]]></programlisting>
<para>
映射中有4个表。<literal>works</literal>, <literal>authors</literal><literal>persons</literal>
分别保存着workauthor和person的数据。<literal>author_work</literal>是authors和works的关联表。
表结构是由<literal>SchemaExport</literal>生成的。
</para>
<programlisting><![CDATA[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]]></programlisting>
</sect1>
<sect1 id="example-mappings-customerorderproduct">
<title>Customer(客户)/Order(订单)/Product(产品)</title>
<para>
现在来考虑<literal>Customer</literal>,<literal>Order</literal> <literal>LineItem</literal>
<literal>Product</literal>关系的模型。<literal>Customer</literal><literal>Order</literal>之间
是一对多的关系,但是我们怎么来描述<literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>呢?
我可以把<literal>LineItem</literal>作为描述<literal>Order</literal><literal>Product</literal>
多对多关系的关联类在Hibernate这叫做组合元素。
</para>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
</imageobject>
</mediaobject>
<para>
映射文件如下:
</para>
<programlisting><![CDATA[<hibernate-mapping>
<class name="Customer" table="customers">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="orders" inverse="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">
<key column="order_id"/>
<list-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>]]></programlisting>
<para>
<literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal>
<literal>products</literal> 分别保存着customer, order, order line item 和 product的数据。
<literal>line_items</literal>也作为连接orders 和 products的关联表。
</para>
<programlisting><![CDATA[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]]></programlisting>
</sect1>
<sect1 id="misc">
<title>杂例</title>
<para>
这些例子全部来自于Hibernate的test suite同时你也可以找到其他有用的例子。
可以参考Hibernate的<literal>src</literal>目录。
</para>
<para>TODO: put words around this stuff</para>
<sect2 id="example-mappings-typed-onetone">
<title>"Typed" one-to-one association</title>
<programlisting><![CDATA[<class name="Person">
<id name="name"/>
<one-to-one name="address"
cascade="all">
<formula>name</formula>
<formula>'HOME'</formula>
</one-to-one>
<one-to-one name="mailingAddress"
cascade="all">
<formula>name</formula>
<formula>'MAILING'</formula>
</one-to-one>
</class>
<class name="Address" batch-size="2"
check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
<composite-id>
<key-many-to-one name="person"
column="personName"/>
<key-property name="type"
column="addressType"/>
</composite-id>
<property name="street" type="text"/>
<property name="state"/>
<property name="zip"/>
</class>]]></programlisting>
</sect2>
<sect2 id="example-mappings-composite-key">
<title>Composite key example</title>
<programlisting><![CDATA[<class name="Customer">
<id name="customerId"
length="10">
<generator class="assigned"/>
</id>
<property name="name" not-null="true" length="100"/>
<property name="address" not-null="true" length="200"/>
<list name="orders"
inverse="true"
cascade="save-update">
<key column="customerId"/>
<index column="orderNumber"/>
<one-to-many class="Order"/>
</list>
</class>
<class name="Order" table="CustomerOrder" lazy="true">
<synchronize table="LineItem"/>
<synchronize table="Product"/>
<composite-id name="id"
class="Order$Id">
<key-property name="customerId" length="10"/>
<key-property name="orderNumber"/>
</composite-id>
<property name="orderDate"
type="calendar_date"
not-null="true"/>
<property name="total">
<formula>
( select sum(li.quantity*p.price)
from LineItem li, Product p
where li.productId = p.productId
and li.customerId = customerId
and li.orderNumber = orderNumber )
</formula>
</property>
<many-to-one name="customer"
column="customerId"
insert="false"
update="false"
not-null="true"/>
<bag name="lineItems"
fetch="join"
inverse="true"
cascade="save-update">
<key>
<column name="customerId"/>
<column name="orderNumber"/>
</key>
<one-to-many class="LineItem"/>
</bag>
</class>
<class name="LineItem">
<composite-id name="id"
class="LineItem$Id">
<key-property name="customerId" length="10"/>
<key-property name="orderNumber"/>
<key-property name="productId" length="10"/>
</composite-id>
<property name="quantity"/>
<many-to-one name="order"
insert="false"
update="false"
not-null="true">
<column name="customerId"/>
<column name="orderNumber"/>
</many-to-one>
<many-to-one name="product"
insert="false"
update="false"
not-null="true"
column="productId"/>
</class>
<class name="Product">
<synchronize table="LineItem"/>
<id name="productId"
length="10">
<generator class="assigned"/>
</id>
<property name="description"
not-null="true"
length="200"/>
<property name="price" length="3"/>
<property name="numberAvailable"/>
<property name="numberOrdered">
<formula>
( select sum(li.quantity)
from LineItem li
where li.productId = productId )
</formula>
</property>
</class>]]></programlisting>
</sect2>
<sect2 id="example-mappings-content-discrimination">
<title>Content based discrimination</title>
<programlisting><![CDATA[<class name="Person"
discriminator-value="P">
<id name="id"
column="person_id"
unsaved-value="0">
<generator class="native"/>
</id>
<discriminator
type="character">
<formula>
case
when title is not null then 'E'
when salesperson is not null then 'C'
else 'P'
end
</formula>
</discriminator>
<property name="name"
not-null="true"
length="80"/>
<property name="sex"
not-null="true"
update="false"/>
<component name="address">
<property name="address"/>
<property name="zip"/>
<property name="country"/>
</component>
<subclass name="Employee"
discriminator-value="E">
<property name="title"
length="20"/>
<property name="salary"/>
<many-to-one name="manager"/>
</subclass>
<subclass name="Customer"
discriminator-value="C">
<property name="comments"/>
<many-to-one name="salesperson"/>
</subclass>
</class>]]></programlisting>
</sect2>
<sect2 id="example-mappings-association-alternatekeys" >
<title>Associations on alternate keys</title>
<programlisting><![CDATA[<class name="Person">
<id name="id">
<generator class="hilo"/>
</id>
<property name="name" length="100"/>
<one-to-one name="address"
property-ref="person"
cascade="all"
fetch="join"/>
<set name="accounts"
inverse="true">
<key column="userId"
property-ref="userId"/>
<one-to-many class="Account"/>
</set>
<property name="userId" length="8"/>
</class>
<class name="Address">
<id name="id">
<generator class="hilo"/>
</id>
<property name="address" length="300"/>
<property name="zip" length="5"/>
<property name="country" length="25"/>
<many-to-one name="person" unique="true" not-null="true"/>
</class>
<class name="Account">
<id name="accountId" length="32">
<generator class="uuid.hex"/>
</id>
<many-to-one name="user"
column="userId"
property-ref="userId"/>
<property name="type" not-null="true"/>
</class>]]></programlisting>
</sect2>
</sect1>
</chapter>