在NHibernate中使用复合外键中的复合主键的一部分

时间:2010-10-08 15:49:11

标签: nhibernate nhibernate-mapping composite-key

我们有一个相当大的数据库(~200个表)几乎完全使用复合主键和复合外键,使用单个“基表”,其他每个表继承其主键的一部分:

  • 父级具有单列主键ParentId
  • Child具有复合主键(ParentId,ChildId)和外键ParentId
  • Nephew有复合主键(ParentId,NephewId),外键ParentId和外键(ParentId,ChildId)

等等。到目前为止,我们使用自己的ORM框架管理整个shebang,但是我们正在考虑使用NHibernate,我已经被分配去学习(我已经下载了v2.1.2)。

映射: 子

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Assembly" namespace="Namespace">
<class name="Child" table="Child">
    <composite-id name="IdChild" class="ChildId">
        <key-many-to-one name="Parent" column="ParentId" class="ParentId"></key-many-to-one>
        <key-property name="Id" column="ChildId" type="Int32"></key-property>
    </composite-id>
    <!--simple properties-->
    <set name="Nephews" table="Nephew">
        <key>
            <column name="ParentId"></column>
            <column name="ChildId"></column>
        </key>
        <one-to-many class="Nephew"/>
    </set>
</class>
</hibernate-mapping> 

Nephew公司

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Assembly" namespace="Namespace">
    <class name="Nephew" table="Nephew">
        <composite-id name="IdNephew" class="NephewId">
            <key-many-to-one name="Parent" column="ParentId" class="Parent"></key-many-to-one>
            <key-property name="Id" column="NephewId" type="Int32"></key-property>
        </composite-id>
        <many-to-one name="Child" class="Child">
            <column name="ParentId"></column>
            <column name="ChildId"></column>
        </many-to-one>
        <!--simple properties-->
    </class>

如果你愿意,我也可以发布课程,为了简洁我现在省略它们(因为我省略了父的映射,因为它没有问题)。每个属性都是虚拟的,每个映射文件都是一个嵌入式资源,每个复合Id都有自己的类,它会覆盖Equals和GetHashCode。

问题是我无法保存Nephew的实例,通过简单的new Nephew()初始化并传递给_session.Save(),因为我得到了System.IndexOutOfRangeException: Invalid index n for this SqlParameterCollection with Count=n.

映射中唯一重复的列是ParentId。删除many-to-one中的Nephew映射,set中的Child映射以及所有相关属性一切正常。

我发现有几个帖子报告了这个异常,在我的情况下最合适的似乎是this one,这让我觉得我的当前的架构在NHibernate中是不可行的。请告诉我我错了: - )

注意:

  • 我现在不使用Fluent,即使它可能是一个选项,但我更喜欢先学习基础知识;
  • 是的,我们意识到复合主键是一个很大的痛苦。多年来,这个数据库已经通过了几手,可能不是那么熟练,但在重构之前我们将数到10 000

2 个答案:

答案 0 :(得分:0)

不幸的是,您将无法以当前形式映射该关系,如您所推断的那样。

然而,有一个解决方法。不要将Nephew.Child映射为多对一,而是将ChildId映射为常规属性,并在需要检索子项时使用查询。

还有一次机会。当且仅当Nephew.Child不为null且不可变时,您可以映射引用Child而不是父项的键:

<class name="Nephew" table="Nephew">
  <composite-id name="IdNephew" class="NephewId">
    <key-many-to-one name="Child">
      <column="ParentId">
      <column="ChildId">
    </key-many-to-one>
    <key-property name="Id" column="NephewId"/>
  </composite-id>
</class>

答案 1 :(得分:0)

我找到了更好的解决方案:

<many-to-one name="Child" class="Child">
    <formula>ParentId</formula>
    <column name="ChildId"></column>
</many-to-one>

我已经尝试了它并且它给了我一个错误,但后来我注意到this patch,所以我下载了3.0.0 alpha2并且一切正常!多亏了这个解决方案,我可以按原样映射Nephew.Child属性。

我仍然需要Child.Add(Nephew)方法(但我意识到即使在文档中也建议这样做)