Hibernate.org Community Documentation

- 上一页
- 下一页

## 第 20 章 XML 映射

XML Mapping is an experimental feature in Hibernate 3.0 and is currently under active development.

## 20.1. 用 XML 数据进行工作

Hibernate 使得你可以用 XML 数据来进行工作，恰如你用持久化的 POJO 进行工作那样。解析过的 XML 树 可以被认为是代替 POJO 的另外一种在对象层面上表示关系型数据的途径。

Hibernate 支持采用 dom4j 作为操作 XML 树的 API。你可以写一些查询从数据库中检索出 dom4j 树，随后你对这颗树做的任何修改都将自动同步回数据库。你甚至可以用 dom4j 解析 一篇 XML 文档，然后使用 Hibernate 的任一基本操作将它写入数据库：`persist()，saveOrUpdate()，merge()，delete()，replicate()` （合并操作merge()目前还不支持）。

这一特性可以应用在很多场合，包括数据导入导出，通过 JMS 或 SOAP 具体化实体数据以及 基于 XSLT 的报表。

一个单一的映射就可以将类的属性和 XML 文档的节点同时映射到数据库。如果不需要映射类，它也可以用来只映射 XML 文档。

### 20.1.1. 指定同时映射 XML 和类

这是一个同时映射 POJO 和 XML 的例子：

    <class name="Account"

            table="ACCOUNTS"

            node="account">

        <id name="accountId"

                column="ACCOUNT_ID"

                node="@id"/>

        <many-to-one name="customer"

                column="CUSTOMER_ID"

                node="customer/@id"

                embed-xml="false"/>

        <property name="balance"

                column="BALANCE"

                node="balance"/>

        ...

    </class

    >

### 20.1.2. 只定义 XML 映射

这是一个不映射 POJO 的例子：

    <class entity-name="Account"

            table="ACCOUNTS"

            node="account">

        <id name="id"

                column="ACCOUNT_ID"

                node="@id"

                type="string"/>

        <many-to-one name="customerId"

                column="CUSTOMER_ID"

                node="customer/@id"

                embed-xml="false"

                entity-name="Customer"/>

        <property name="balance"

                column="BALANCE"

                node="balance"

                type="big_decimal"/>

        ...

    </class

    >

这个映射使得你既可以把数据作为一棵 dom4j 树那样访问，又可以作为由属性键值对（java `Map`）组成的图那样访问。属性名字纯粹是逻辑上的结构，你可以在 HQL 查询中引用它。

## 20.2. XML 映射元数据

许多 Hibernate 映射元素具有 `node` 属性。这使你可以指定用来保存 属性或实体数据的 XML 属性或元素。`node` 属性必须是下列格式之一：

- `"element-name"`：映射为指定的 XML 元素

- `"@attribute-name"`：映射为指定的 XML 属性

- `"."`：映射为父元素

- `"element-name/@attribute-name"`：映射为指定元素的指定属性

对于集合和单值的关联，有一个额外的 `embed-xml` 属性可用。这个属性的缺省值是真（`embed-xml="true"`）。如果 `embed-xml="true"`，则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的 XML 树中。否则，如果 `embed-xml="false"`，那么对于单值的关联，仅被引用的实体的标识符出现在 XML 树中（被引用实体本身不出现），而集合则根本不出现。

你应该小心，不要让太多关联的 embed-xml 属性为真（`embed-xml="true"`），因为 XML 不能很好地处理循环引用。

    <class name="Customer"

            table="CUSTOMER"

            node="customer">

        <id name="id"

                column="CUST_ID"

                node="@id"/>

        <map name="accounts"

                node="."

                embed-xml="true">

            <key column="CUSTOMER_ID"

                    not-null="true"/>

            <map-key column="SHORT_DESC"

                    node="@short-desc"

                    type="string"/>

            <one-to-many entity-name="Account"

                    embed-xml="false"

                    node="account"/>

        </map>

        <component name="name"

                node="name">

            <property name="firstName"

                    node="first-name"/>

            <property name="initial"

                    node="initial"/>

            <property name="lastName"

                    node="last-name"/>

        </component>

        ...

    </class

    >

在这个例子中，我们决定嵌入帐目号码（account id）的集合，但不嵌入实际的帐目数据。下面的 HQL 查询：

    from Customer c left join fetch c.accounts where c.lastName like :lastName

返回的数据集将是这样：

    <customer id="123456789">

        <account short-desc="Savings"

    >987632567</account>

        <account short-desc="Credit Card"

    >985612323</account>

        <name>

            <first-name

    >Gavin</first-name>

            <initial

    >A</initial>

            <last-name

    >King</last-name>

        </name>

        ...

    </customer

    >

如果你把一对多映射 `<one-to-many>` 的 embed-xml 属性置为真（`embed-xml="true"`），则数据看上去就像这样：

    <customer id="123456789">

        <account id="987632567" short-desc="Savings">

            <customer id="123456789"/>

            <balance

    >100.29</balance>

        </account>

        <account id="985612323" short-desc="Credit Card">

            <customer id="123456789"/>

            <balance

    >-2370.34</balance>

        </account>

        <name>

            <first-name

    >Gavin</first-name>

            <initial

    >A</initial>

            <last-name

    >King</last-name>

        </name>

        ...

    </customer

    >

## 20.3. 操作 XML 数据

你也可以重新读入和更新应用程序中的 XML 文档。通过获取一个 dom4j 会话可以做到这一点：

    Document doc = ....;

    Session session = factory.openSession();

    Session dom4jSession = session.getSession(EntityMode.DOM4J);

    Transaction tx = session.beginTransaction();

    List results = dom4jSession

        .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")

        .list();

    for ( int i=0; i<results.size(); i++ ) {

        //add the customer data to the XML document

        Element customer = (Element) results.get(i);

        doc.add(customer);

    }

    tx.commit();

    session.close();

    Session session = factory.openSession();

    Session dom4jSession = session.getSession(EntityMode.DOM4J);

    Transaction tx = session.beginTransaction();

    Element cust = (Element) dom4jSession.get("Customer", customerId);

    for ( int i=0; i<results.size(); i++ ) {

        Element customer = (Element) results.get(i);

        //change the customer name in the XML and database

        Element name = customer.element("name");

        name.element("first-name").setText(firstName);

        name.element("initial").setText(initial);

        name.element("last-name").setText(lastName);

    }

    tx.commit();

    session.close();

将这一特色与 Hibernate 的 `replicate()` 操作结合起来对于实现的基于 XML 的数据导入/导出将非常有用。

版权 © 2004 Red Hat, Inc.

- 上一页第 19 章 过滤数据
- 上一级
- 起始页
- 下一页第 21 章 提升性能