第 3 章 通过XML覆写元数据

在EJB3中元数据的主要目标是使用注释,但是EJB3规范也提供通过XML部署文件来覆写或者替换元数据注释. 在当前的发布版本仅仅支持EJB3注释的覆写,如果你想使用Hibernate特有的一些实体注释, 你有两种选择:一,只使用注释;二,使用原来的hbm 映射文件.你当然还是可以同时使用注释实体和hbm XML映射文件的实体.

在测试套件中有一些附加的XML文件的样例.

3.1. 原则

XML部署文件结构被设计为直接映射注释结构,所以如果你知道注释的结构,那么使用XML语法是很简单的.

你可以定义一个或者多个XML文件来描述你的元数据,这些文件会被覆写引擎合并(merged).

3.1.1. 全局级别的元数据

你可以使用XML文件来定义全局元数据,对每一个部署文件你不能定义多于一个的元数据.

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings 
  xmlns="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
  version="1.0">

    <persistence-unit-metadata>
        <xml-mapping-metadata-complete/>
        <persistence-unit-defaults>
            <schema>myschema</schema>
            <catalog>mycatalog</catalog>
            <cascade-persist/>
        </persistence-unit-defaults>
    </persistence-unit-metadata>

xml-mapping-metadata-complete 意味着所有的实体,mapped-superclasses和嵌套的元数据应该从XML文件中启用(忽略注释).

schema / catalog 将覆写所有在元数据中默认定义的schema 和 catalog(包括XML和注释).

cascade-persist 意味着所有注释作为一个 cascade type 都是PERSIST的. 我们推荐你不要使用该特性.

3.1.2. 实体级别的元数据

你也可以在一个给定的实体上定义或者覆写元数据

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings                                                                    (1)
  xmlns="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
  version="1.0">

    <package>org.hibernate.test.annotations.reflection</package>                    (2)
    <entity class="Administration" access="PROPERTY" metadata-complete="true">      (3)
        <table name="tbl_admin">                                                    (4)
            <unique-constraint>
                <column-name>firstname</column-name>
                <column-name>lastname</column-name>
            </unique-constraint>
        </table>
        <secondary-table name="admin2">                                             (5)
            <primary-key-join-column name="admin_id" referenced-column-name="id"/>
            <unique-constraint>
                <column-name>address</column-name>
            </unique-constraint>
        </secondary-table>
        <id-class class="SocialSecurityNumber"/>                                    (6)
        <inheritance strategy="JOINED"/>                                            (7)
        <sequence-generator name="seqhilo" sequence-name="seqhilo"/>                (8)
        <table-generator name="table" table="tablehilo"/>                           (9)
        ...
    </entity>

    <entity class="PostalAdministration">
        <primary-key-join-column name="id"/>                                        (10)
        ...
    </entity>
</entity-mappings>
(1)

entity-mappings:entity-mappings 是所有XML文件的根元素.你必须定义XML Schema, 该文件包含在hibernate-annotations.jar中,使用Hibernate Annotations 不需要访问网络.

(2)

package (可选的): 作为默认的package用于在一个给定的部署描述文件中所有没有限定的类.

(3)

entity: 描述一个实体.

metadata-complete 定义对于该元素是否全部使用元数据(换句话来说就是,如果注释出现在类级别应该考虑或者忽略).

一个实体不得不有一个 class 属性来引用 元数据所应用的类.

通过name属性你可以覆写实体的名字, 如果没有定义并且@Entity.name出现了的话,那么就使用该注释(假如metadata complete 没有被设置).

对于metadata complete (参考下面)元素, 你可以定义一个 access(FIELD 或者 PROPERTY(默认值)), 对于非metadata complete 元素,使用注释的access type.

(4)

table: 你可以声明table 属性(name, schema, catalog), 如果没有定义, 将使用Java注释.

就象例子中所示的那样你可以定义一个或者多个unique constraints

(5)

secondary-table: 定义一个secondary-table,除了你可以通过primary-key-join-column 元素定义 primary key / foreign key 列以外是和一般的table一样的. 在非metadata complete下, annotation secondary tables 仅仅在没有secondary-table 定义的情况下使用, 否则 注释将被忽略.

(6)

id-class: 和@IdClass一样定义一个id class.

(7)

inheritance: 定义继承策略(JOINED, TABLE_PER_CLASS, SINGLE_TABLE), 仅仅在根实体级别可以使用.

(8)

sequence-generator: 定义一个序列产生器.

(9)

table-generator: 定义一个table generator

(10)

primary-key-join-column: 当 JOINED 继承策略使用时,为sub entities定义一个 primary key join column.

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings 
  xmlns="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
  version="1.0">

    <package>org.hibernate.test.annotations.reflection</package>
    <entity class="Music" access="PROPERTY" metadata-complete="true">
        <discriminator-value>Generic</discriminator-value>                          (1)
        <discriminator-column length="34"/>
        ...
    </entity>

    <entity class="PostalAdministration">
        <primary-key-join-column name="id"/>
        <named-query name="adminById">                                              (2)
            <query>select m from Administration m where m.id = :id</query>
            <hint name="org.hibernate.timeout" value="200"/>
        </named-query>
        <named-native-query name="allAdmin" result-set-mapping="adminrs">           (3)
            <query>select *, count(taxpayer_id) as taxPayerNumber 
            from Administration, TaxPayer
            where taxpayer_admin_id = admin_id group by ...</query>
            <hint name="org.hibernate.timeout" value="200"/>
        </named-native-query>
        <sql-result-set-mapping name="adminrs">                                     (4)
            <entity-result entity-class="Administration">
                <field-result name="name" column="fld_name"/>
            </entity-result>
            <column-result name="taxPayerNumber"/>
        </sql-result-set-mapping>
        <attribute-override name="ground">                                          (5)
            <column name="fld_ground" unique="true" scale="2"/>
        </attribute-override>
        <association-override name="referer">
            <join-column name="referer_id" referenced-column-name="id"/>
        </association-override>
        ...
    </entity>
</entity-mappings>
(1)

discriminator-value / discriminator-column: 当SINGLE_TABLE继承策略使用时,定义鉴别器值 和 保存该值的列.

(2)

named-query: 定义命名查询和一些相关的可能的线索. 该定义附加在注释的定义中,如果两个都定义了相同的名字,那么XML将优先考虑.

(3)

named-native-query: 定义一个命名本地查询 和他的 sql result set 映射. 作为另外一种选择,你可以定义result-class. 这些定义附加在注释的定义中.如果两个定义了同样的名字,XML文件优先考虑.

(4)

sql-result-set-mapping: 描述了 result set mapping 的结构. 你可以定义 实体和列映射. 这些定义附加在注释的定义中,如果定义了同样的名字,XML文件优先考虑.

(5)

attribute-override / association-override: 定义一列或者join column overriding. 该overriding 附加在注释的定义中.

一些应用于 <embeddable><mapped-superclass>.

3.1.3. 属性级别的元数据

你当然可以定义XML来覆写属性. 如果metadata complete 给定义了,那么附加的属性(如: 在Java 级别的)将被忽略. 另外,一旦你开始覆写一个属性,在该属性上的所有注释都会被忽略.所有属性级别的元数据应用于entity/attributes, mapped-superclass/attributesembeddable/attributes.

    <attributes>
        <id name="id">
            <column name="fld_id"/>
            <generated-value generator="generator" strategy="SEQUENCE"/>
            <temporal>DATE</temporal>
            <sequence-generator name="generator" sequence-name="seq"/>
        </id>
        <version name="version"/>
        <embedded name="embeddedObject">
            <attribute-override name"subproperty">
                <column name="my_column"/>
            </attribute-override>
        </embedded>
        <basic name="status" optional="false">
            <enumerated>STRING</enumerated>
        </basic>
        <basic name="serial" optional="true">
            <column name="serialbytes"/>
            <lob/>
        </basic>
        <basic name="terminusTime" fetch="LAZY">
            <temporal>TIMESTAMP</temporal>
        </basic>
    </attributes>

通过 id, embedded-id, version, embeddedbasic你可以覆写一个属性, 这些元素中的每一个元素都有相应的subelements:lob, temporal, enumerated, column.

3.1.4. 关联级别的元数据

你可以定义XML覆写关联注释. 所有的关联级别的元数据作用于 entity/attributes, mapped-superclass/attributesembeddable/attributes.

    <attributes>
        <one-to-many name="players" fetch="EAGER">
            <map-key name="name"/>
            <join-column name="driver"/>
            <join-column name="number"/>
        </one-to-many>
        <many-to-many name="roads" target-entity="Administration">
            <order-by>maxSpeed</order-by>
            <join-table name="bus_road">
                <join-column name="driver"/>
                <join-column name="number"/>
                <inverse-join-column name="road_id"/>
                <unique-constraint>
                    <column-name>driver</column-name>
                    <column-name>number</column-name>
                </unique-constraint>
            </join-table>
        </many-to-many>
        <many-to-many name="allTimeDrivers" mapped-by="drivenBuses">
    </attributes>

通过one-to-many, one-to-one, many-to-one, 和 many-to-many. 你可以重写一个关联关系.这些元素中的每一个都有相应的subelements. join-table (可以有 join-columninverse-join-column), join-column, map-key, 和 order-by. mapped-bytarget-entity 当他们有意义的时候可以定义属性. 再一次强调 该结构映射于注释的结构.在描述注释的一章中 你可以找到所有的语义信息.