271 lines
9.1 KiB
XML
271 lines
9.1 KiB
XML
<chapter id="xml">
|
||
<title>XML映射</title>
|
||
<para><emphasis>
|
||
注意这是Hibernate 3.0的一个实验性的特性。这一特性仍在积极开发中。
|
||
</emphasis></para>
|
||
|
||
<sect1 id="xml-intro" revision="1">
|
||
<title>用XML数据进行工作</title>
|
||
|
||
<para>
|
||
Hibernate使得你可以用XML数据来进行工作,恰如你用持久化的POJO进行工作那样。解析过的XML树
|
||
可以被认为是另外一种在对象层面上代替POJO来表示关系型数据的途径.
|
||
</para>
|
||
|
||
<para>
|
||
Hibernate支持采用dom4j作为操作XML树的API。你可以写一个查询从数据库中检索出
|
||
dom4j树,随后你对这颗树做的任何修改都将自动同步回数据库。你甚至可以用dom4j解析
|
||
一篇XML文档,然后使用Hibernate的任一基本操作将它写入数据库:
|
||
<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
|
||
(合并操作merge()目前还不支持)。
|
||
</para>
|
||
|
||
<para>
|
||
这一特性可以应用在很多场合,包括数据导入导出,通过JMS或SOAP表现实体数据以及
|
||
基于XSLT的报表。
|
||
</para>
|
||
|
||
<para>
|
||
一个单一的映射就可以将类的属性和XML文档的节点同时映射到数据库。如果不需要映射类,
|
||
它也可以用来只映射XML文档。
|
||
</para>
|
||
|
||
<sect2 id="xml-intro-mapping">
|
||
<title>指定同时映射XML和类</title>
|
||
|
||
<para>
|
||
这是一个同时映射POJO和XML的例子:
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<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>]]></programlisting>
|
||
</sect2>
|
||
|
||
<sect2 id="xml-onlyxml">
|
||
<title>只定义XML映射</title>
|
||
|
||
<para>
|
||
这是一个不映射POJO的例子:
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<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>]]></programlisting>
|
||
|
||
<para>
|
||
这个映射使得你既可以把数据作为一棵dom4j树那样访问,又可以作为由属性键值对(java <literal>Map</literal>s)
|
||
组成的图那样访问。属性名字是纯粹逻辑上的结构,你可以在HQL查询中引用它。
|
||
</para>
|
||
|
||
</sect2>
|
||
|
||
</sect1>
|
||
|
||
<sect1 id="xml-mapping" revision="1">
|
||
<title>XML映射元数据</title>
|
||
|
||
<para>
|
||
许多Hibernate映射元素具有<literal>node</literal>属性。这使你可以指定用来保存
|
||
属性或实体数据的XML属性或元素。<literal>node</literal>属性必须是下列格式之一:
|
||
</para>
|
||
|
||
<itemizedlist spacing="compact">
|
||
<listitem>
|
||
<para><literal>"element-name"</literal> - 映射为指定的XML元素</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para><literal>"@attribute-name"</literal> - 映射为指定的XML属性</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para><literal>"."</literal> - 映射为父元素</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
<literal>"element-name/@attribute-name"</literal> -
|
||
映射为指定元素的指定属性
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
对于集合和单值的关联,有一个额外的<literal>embed-xml</literal>属性可用。
|
||
这个属性的缺省值是真(<literal>embed-xml="true"</literal>)。如果<literal>embed-xml="true"</literal>,
|
||
则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的XML树中。
|
||
否则,如果<literal>embed-xml="false"</literal>,那么对于单值的关联,仅被引用的实体的标识符出现在
|
||
XML树中(被引用实体本身不出现),而集合则根本不出现。
|
||
</para>
|
||
|
||
<para>
|
||
你应该小心,不要让太多关联的embed-xml属性为真(<literal>embed-xml="true"</literal>),因为XML不能很好地处理
|
||
循环引用!
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<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>]]></programlisting>
|
||
|
||
<para>
|
||
在这个例子中,我们决定嵌入帐目号码(account id)的集合,但不嵌入实际的帐目数据。下面的HQL查询:
|
||
</para>
|
||
|
||
<programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
|
||
|
||
<para>
|
||
返回的数据集将是这样:
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<customer id="123456789">
|
||
<account id="987632567" short-desc="Savings"/>
|
||
<account id="985612323" short-desc="Credit Card"/>
|
||
<name>
|
||
<first-name>Gavin</first-name>
|
||
<initial>A</initial>
|
||
<last-name>King</last-name>
|
||
</name>
|
||
...
|
||
</customer>]]></programlisting>
|
||
|
||
<para>
|
||
如果你把一对多映射<literal><one-to-many></literal>的embed-xml属性置为真(<literal>embed-xml="true"</literal>),
|
||
则数据看上去就像这样:
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<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>]]></programlisting>
|
||
|
||
</sect1>
|
||
|
||
|
||
<sect1 id="xml-manipulation" revision="1">
|
||
<title>操作XML数据</title>
|
||
|
||
<para>
|
||
让我们来读入和更新应用程序中的XML文档。通过获取一个dom4j会话可以做到这一点:
|
||
</para>
|
||
|
||
<programlisting><![CDATA[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();]]></programlisting>
|
||
|
||
<programlisting><![CDATA[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();]]></programlisting>
|
||
|
||
<para>
|
||
将这一特色与Hibernate的<literal>replicate()</literal>操作结合起来而实现的基于XML的数据导入/导出将非常有用.
|
||
</para>
|
||
|
||
</sect1>
|
||
|
||
</chapter>
|