• NHibernate官方文档——第八章 继承映射(Inheritance Mapping)


    本文翻译自NHibernate官方文档NHibernate Reference Documentation 4.1

    受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助。

    侵删。

    关于继承映射的三个继承映射方案

    NHibernate支持三个基本的继承映射隐射方案。

      • 一个继承一张表(table per class hierarchy)

      • 一个子类额外信息一张表(table per subclass)

      • 一个子类全部信息一张表(table per concrete class)

    NHibernate还支持第四种,比较特殊的一种多态:

      • 隐式多态(implicit polymorphism)

    针对不同的继承结构,我们可以使用不同的映射方案,然后使用隐式多态去获得整个继承关系中的多态属性。然而NHibernate不支持在一个<class>标签下面混合使用<subclass>,<joined-subclass>和<union-subclass>三种映射。然而,通过使用<subclass>和<join>标签,NHibernate支持将一个继承一张表(table per hierarchy )和一个子类额外信息一张表(table per subclass)两种映射方案混合在同一个<class>标签下面使用(见下文)。

    NHibernate也支持将subclass,union-subclass和joined-subclass的mapping分散在不同文件中,我们可以直接在各个文件的<hibernate-mapping>标签中定义类的mapping。这样就可以让你能够通过增加mapping文件来扩展整个类的层级结构。当然你必须在子类的mapping文件中设置extends属性来指向它的父类。

     <hibernate-mapping>
         <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
              <property name="name" type="string"/>
         </subclass>
     </hibernate-mapping>

    一个继承一张表(table per class hierarchy)

    假设我们有一个IPayment接口,有CreditCardPayment, CashPayment,ChequePayment三种实现方式。这种一个继承一张表的配置是这样:

    <class name="IPayment" table="PAYMENT">
        <id name="Id" type="Int64" column="PAYMENT_ID">
            <generator class="native"/>
        </id>
        <discriminator column="PAYMENT_TYPE" type="String"/>
        <property name="Amount" column="AMOUNT"/>
        ...
        <subclass name="CreditCardPayment" discriminator-value="CREDIT">
            ...
        </subclass>
        <subclass name="CashPayment" discriminator-value="CASH">
            ...
        </subclass>
        <subclass name="ChequePayment" discriminator-value="CHEQUE">
            ...
        </subclass>
    </class>

    只需要一张表就可以了,但是这种方式有一个局限性:子类对应的列不能有NOT NULL的限制。

    一个子类额外信息一张表(table per subclass)

    一个一个子类额外信息一张表的配置是这样:

    <class name="IPayment" table="PAYMENT">
        <id name="Id" type="Int64" column="PAYMENT_ID">
            <generator class="native"/>
        </id>
        <property name="Amount" column="AMOUNT"/>
        ...
        <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
            <key column="PAYMENT_ID"/>
            ...
        </joined-subclass>
        <joined-subclass name="CashPayment" table="CASH_PAYMENT">
            <key column="PAYMENT_ID"/>
            ...
        </joined-subclass>
        <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
            <key column="PAYMENT_ID"/>
            ...
        </joined-subclass>
    </class>

    这种配置方式需要四张表。三张字表的主键和父表关联(他们之间的关系实际上是一对一关系)。

    一个子类全部信息一张表(table per concrete class),使用一个区分字段

    我们注意到,在NHibernate中,一个子类额外信息一张表(table per subclass)的实现方式不需要区分字段,其他的实体/关系映射工具使用了一种不同的实现方式:他们的父表设置了一个区分类型的字段。NHibernate使用了一种更麻烦但是关系描述角度来看更加准确的的实现方式。如果你想在一个子类额外信息一张表的方式上实现区分字段,你需要把<subclass>和<join>标签结合起来使用如下:

    <class name="Payment" table="PAYMENT">
        <id name="Id" type="Int64" column="PAYMENT_ID">
            <generator class="native"/>
        </id>
        <discriminator column="PAYMENT_TYPE" type="string"/>
        <property name="Amount" column="AMOUNT"/>
        ...
        <subclass name="CreditCardPayment" discriminator-value="CREDIT">
            <join table="CREDIT_PAYMENT">
                <key column="PAYMENT_ID"/>
                <property name="CreditCardType" column="CCTYPE"/>
                ...
            </join>
        </subclass>
        <subclass name="CashPayment" discriminator-value="CASH">
            <join table="CASH_PAYMENT">
                <key column="PAYMENT_ID"/>
                ...
            </join>
        </subclass>
        <subclass name="ChequePayment" discriminator-value="CHEQUE">
            <join table="CHEQUE_PAYMENT" fetch="select">
                <key column="PAYMENT_ID"/>
                ...
            </join>
        </subclass>
    </class>

    可选字段fetch="select"的声明告诉NHibernate在查询的时候不要使用outer join获得ChequePayment的子类。

    父类信息和子类信息混合在同一张表内(Mixing table per class hierarchy with table per subclass)

    你甚至可以将一个继承一张表(table per class hierarchy)和一个子类额外信息一张表(table per subclass)两种方式结合:

    <class name="Payment" table="PAYMENT">
        <id name="Id" type="Int64" column="PAYMENT_ID">
            <generator class="native"/>
        </id>
        <discriminator column="PAYMENT_TYPE" type="string"/>
        <property name="Amount" column="AMOUNT"/>
        ...
        <subclass name="CreditCardPayment" discriminator-value="CREDIT">
            <join table="CREDIT_PAYMENT">
                <property name="CreditCardType" column="CCTYPE"/>
                ...
            </join>
        </subclass>
        <subclass name="CashPayment" discriminator-value="CASH">
            ...
        </subclass>
        <subclass name="ChequePayment" discriminator-value="CHEQUE">
            ...
        </subclass>
    </class>

    对于这些mapping的方式,要使用<many-to-one>映射一个IPayment的多态连接。

    <many-to-one name="Payment" column="PAYMENT" class="IPayment"/>

    一个子类全部信息一张表(table per concrete class)

    有两种方式可以实现,第一种方式是使用<union-subclass>

    <class name="Payment">
        <id name="Id" type="Int64" column="PAYMENT_ID">
            <generator class="sequence"/>
        </id>
        <property name="Amount" column="AMOUNT"/>
        ...
        <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
            <property name="CreditCardType" column="CCTYPE"/>
            ...
        </union-subclass>
        <union-subclass name="CashPayment" table="CASH_PAYMENT">
            ...
        </union-subclass>
        <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
            ...
        </union-subclass>
    </class>

    三个类分别表示三个表,每个表都定义了类的所有属性,也包括继承过来的属性。

    这种方式的缺点在于如果属性继承自父类,那么列名在子类中必须完全一样。(我们可能在将来的版本中解决这个问题)序列的生成方式不能独立,主键种子(primary key seed)不许在所有union的子类中共用。

    如果你的父类是abstract,就需要设置abstract="true"。当然,如果它不是abstract的,那么久需要一个额外的表(就像上面的一个继承一张表例子那样)来装父类的实例。

    一个子类全部信息一张表,使用隐式多态(Table per concrete class, using implicit polymorphism)

    另外的一个方式是使用隐式多态:

    <class name="CreditCardPayment" table="CREDIT_PAYMENT">
        <id name="Id" type="Int64" column="CREDIT_PAYMENT_ID">
            <generator class="native"/>
        </id>
        <property name="Amount" column="CREDIT_AMOUNT"/>
        ...
    </class>
    
    <class name="CashPayment" table="CASH_PAYMENT">
        <id name="Id" type="Int64" column="CASH_PAYMENT_ID">
            <generator class="native"/>
        </id>
        <property name="Amount" column="CASH_AMOUNT"/>
        ...
    </class>
    
    <class name="ChequePayment" table="CHEQUE_PAYMENT">
        <id name="Id" type="Int64" column="CHEQUE_PAYMENT_ID">
            <generator class="native"/>
        </id>
        <property name="Amount" column="CHEQUE_AMOUNT"/>
        ...
    </class>

    我们可以注意到,我们不必要显示地声明IPayment接口。同时,我们也可以发现IPayment接口被映射到了在各个具体实现类上面了。如果你想要避免重复,可以考虑使用XML实体(例如,在mapping文件的DOCTYPE声明和&allproperties中[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] )

    这种方式的缺点在于NHibernate在执行多态查询的时候不会产生SQL Union语句。

    <any name="Payment" meta-type="string" id-type="Int64">
        <meta-value value="CREDIT" class="CreditCardPayment"/>
        <meta-value value="CASH" class="CashPayment"/>
        <meta-value value="CHEQUE" class="ChequePayment"/>
        <column name="PAYMENT_CLASS"/>
        <column name="PAYMENT_ID"/>
    </any>

    隐射多态混合其他的继承映射(Mixing implicit polymorphism with other inheritance mappings)

    关于隐式多态还有一个需要注意的地方。因为子类的映射在各自的<class>标签之中配置(因为IPayment只是一个接口),每一个子类又有可能是其他的table-per-class或者table-per-subclass继承结构中的一员!(当然你可以继续使用IPayment的多态查询)

    <class name="CreditCardPayment" table="CREDIT_PAYMENT">
        <id name="Id" type="Int64" column="CREDIT_PAYMENT_ID">
            <generator class="native"/>
        </id>
        <discriminator column="CREDIT_CARD" type="String"/>
        <property name="Amount" column="CREDIT_AMOUNT"/>
        ...
        <subclass name="MasterCardPayment" discriminator-value="MDC"/>
        <subclass name="VisaPayment" discriminator-value="VISA"/>
    </class>
    
    <class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
        <id name="Id" type="Int64" column="TXN_ID">
            <generator class="native"/>
        </id>
        ...
        <joined-subclass name="CashPayment" table="CASH_PAYMENT">
            <key column="PAYMENT_ID"/>
            <property name="Amount" column="CASH_AMOUNT"/>
            ...
        </joined-subclass>
        <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
            <key column="PAYMENT_ID"/>
            <property name="Amount" column="CHEQUE_AMOUNT"/>
            ...
        </joined-subclass>
    </class>

    和上面的例子一样,我们仍然不需要显示声明IPayment接口。如果我们查询了一个IPayment接口的一个实例——例如,from IPayment——NHibernate就会自动返回CreditCardPayment(和它的子类,因为他们也实现了IPayment接口),CashPayment和ChequePayment的实例,但是不会返回NonelectronicTransaction的实例。

    局限性

    对于实现“隐式多态”的“一个子类全部信息一张表”方式,存在一些局限。如果使用<union-subclass>映射方式相对会少一些限制。

    以下表格展示了NHibernate中一个子类全部信息一张表和隐式多态的映射方式的限制情况。

    表格 继承映射的一些特性

    继承类型 多对一的多态 一对一的多态 一对多的多态 多对多的多态 多态的load()/get() 多态查询 多态连接 外连接fetching的支持情况
    一个继承一张表(table per class-hierarchy) <many-to-one> <one-to-one> <one-to-many> <many-to-many> s.Get<IPayment>(id) from IPayment p from Order o join o.Payment p supported
    一个子类额外信息一张表(table per subclass) <many-to-one> <one-to-one> <one-to-many> <many-to-many> s.Get<IPayment>(id) from IPayment p from Order o join o.Payment p supported
    一个子类全部信息一张表(table per concrete-class (union-subclass)) <many-to-one> <one-to-one> <one-to-many>(for inverse="true"only) <many-to-many> s.Get<IPayment>(id) from IPayment p from Order o join o.Payment p supported
    一个子类全部信息一张表(table per concrete class (implicit polymorphism)) <any>

    not supported

    not supported <many-to-many> use a query from IPayment p


    not supported

    not supported
  • 相关阅读:
    为什么要选择忍者站群?
    SDCMS1.31 如何发布?
    强大的忍者站群
    出现未能加载“OpenWebKitSharp”是什么原因?
    wordpress发布模块如何使用?
    忍者站群做了百度竞价,岂不是跟站群相违背吗?
    点点博客的发布模块,如何使用?
    为什么有时候明明提示登陆成功,却无法获取分类或无法发布?
    被百度K了,怎么办?
    笔记0611
  • 原文地址:https://www.cnblogs.com/balavatasky/p/6039936.html
Copyright © 2020-2023  润新知