2010-10-08 105 views
1

我们有一个相当大的DB(~200个表),它几乎完全使用复合主键和复合外键,使用一个“基表”其他表继承其主键的一部分:在NHibernate中使用复合主键的一部分

  • 父具有单个列主键的ParentId
  • 孩子有复合主键(的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的映射,因为它没有问题)。每个属性都是虚拟的,每个映射文件都是嵌入式资源,每个复合标识都有自己的类,它会覆盖Equals和GetHashCode。

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

在映射中重复的唯一列是ParentId。删除Nephew中的many-to-one映射,Child中的set映射和所有相关的属性都可以正常工作。

我发现了几个帖子报告这个例外,并且在我的情况最合适的似乎是this one,这给我的直觉,我当前模式是不可行与NHibernate。请告诉我,我错了:-)

注:

  • 我不使用流利,现在,即使它可能是一种选择,但我更喜欢先学的基础知识;
  • 是的,我们认识到复合主键是屁股上的一大痛苦。该DB已经经历了几手穿过岁月的流逝,恐怕不是那么熟练的,但重构之前,我们会统计到10 000

回答

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)方法,虽然(但我意识到,即使在文档建议)

0

不幸的是,你将无法映射这种关系目前的形式,正如你所推断的那样。

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

还有一个黑客机会。当且仅当Nephew.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> 
+0

谢谢。你的第一个建议部分起作用,但我失去了只通过调用_session.Save(child)级联保存侄子的能力。我必须手动创建一个Child.Add(Nephew)方法,将侄子添加到Nephews集合中,并在侄子中设置简单属性ChildId,即使在标记中使用inverse =“true”和cascade =“all”。它仍然是没有什么 – Piddu 2010-10-11 13:57:44

+0

对不起,我仍然在学习使用本网站作为“学生” – Piddu 2010-10-11 14:21:36

+0

这很好。 FAQ是你的朋友:-) http://stackoverflow.com/faq – 2010-10-11 14:24:31