1

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

  • Parent 有单列主键 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> 

侄子

<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>

如果您愿意,我也可以发布课程,为了简洁起见,我现在将省略它们(因为我将省略 Parent 的映射,因为它没有问题)。每个属性都是虚拟的,每个映射文件都是嵌入式资源,每个复合 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和所有相关属性一切正常。

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

笔记:

  • 我现在没有使用 Fluent,尽管它可能是一种选择,但我更喜欢先学习基础知识;
  • 是的,我们意识到复合主键是一个很大的麻烦。这个数据库多年来经过了好几手,可能不是那么熟练的人,但在重构它之前,我们将数到 10 000
4

2 回答 2

0

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

但是,有一种解决方法。与其将映射Nephew.Child作为多对一映射,不如将其映射ChildId为常规属性,并在需要检索 Child 时使用查询。

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

<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>
于 2010-10-08T17:20:08.467 回答
0

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

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

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

不过,我仍然需要该Child.Add(Nephew)方法(但我意识到即使在文档中也推荐使用该方法)

于 2010-10-13T07:22:50.703 回答