0

我有一个聚合 FreightDateTime 类的寄售类。同时,FreightDateTime 类也被 GoodsItem 类聚合。同样,FreightDateTime 与我暂时忽略的许多其他类相关联。

为了避免使用 ConsignmentId 外键、GoodsItemId 外键等的数据库表 FreightDateTime。我决定关联应该是多对多的。这样,NHibernate 将为每个关系生成一个关联表(ConsigmentFreightDateTimes,GoodsItemFreightDateTimes),这更有意义。

因此,在映射文件中,关联看起来像这样:

<bag name="DateTimes" table="FreightDateTimes" lazy="false" cascade="all">
  <key column="ConsignmentId"/>
  <many-to-many class="Logistics.FreightDateTime, Logistics" column="DateTimeId" />
</bag>

将级联设置为“全部”会产生:

System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'DateTimeId', table 'LogiGate.dbo.FreightDateTimes'; column does not allow nulls. INSERT fails. 

将级联设置为“无”产生:

NHibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Logistics.FreightDateTime

在这两种情况下,这意味着 NHibernate 正在尝试保存 Consignment 实例,尽管尚未保存子 FreightDateTime 实例。在第一种情况下,外键仍然是'null',因此不能插入到结果表中,而在第二种情况下,NHibernate 知道该实例尚未保存,因此抛出异常。

所以问题是我怎样才能让 NHibernate 先保存所有子实例而不明确告诉它这样做。我有预感,允许 DateTimeId 列上的空值可以解决问题,但我认为这既不可取也不可能。

4

1 回答 1

1

尝试在另一侧映射关联,但在该侧使用 inverse="true" 属性。因此,在 FreightDateTime 映射文件中创建一个包以将关联映射为与寄售的多对多。

另外,我在这里回答了一个类似的问题:在 NHibernate 中定义多对多关系以允许删除但避免重复记录的正确方法是什么

阅读问题和我的答案可能会帮助您了解多对多关联的情况,并可能为您提供解决方案的提示。最后的建议是最后的手段。

上述问题的答案只是为了让您了解另一个人的不同问题正在经历什么。

一种解决方案是显式映射关联表。如果您的表是:Person、Note 和关联表(X 表)是 PersonNote 您的映射应该如下所示:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="..."
                   namespace="...">

  <class name="Person" table="Person" lazy="true">

    <id name="PersonId">
      <generator class="native" />
    </id>
    <property name="FirstName" />
    .....
    <bag name="PersonNotes" generic="true" inverse="true" lazy="true" cascade="none">
        <key column="PersonId"/>
        <one-to-many class="PersonNote"/>
    </bag>

    <bag name="Notes" table="PersonNote" cascade="save-update">
      <key column="PersonId"></key>
      <many-to-many class="Note" column="NoteId"></many-to-many>
    </bag>

  </class>

</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="..."
                   namespace="...">

  <class name="Note" table="Note" lazy="true">

    <id name="NoteId" unsaved-value="0">
      <generator class="native" />
    </id>
    <property name="Title" />
    ....
    <bag name="PersonNotes" inverse="true" lazy="true" cascade="all-delete-orphan">
        <key column="NoteId"/>
        <one-to-many class="PersonNote"/>
    </bag>

    <bag name="People" table="PersonNote" inverse="true" cascade="save-update" generic="true">
      <key column="NoteId"></key>
      <many-to-many class="Person" column="PersonId"></many-to-many>
    </bag>

  </class>

</hibernate-mapping>

如上所述,它允许您执行以下操作:

  1. 删除一个人,只删除关联表中的条目,不删除任何注释
  2. 删除一个 Note 并且只删除关联表中的条目而不删除任何 Person 实体
  3. 通过填充 Person.Notes 集合并保存 Person,仅从 Person 端使用 Cascades 保存。
  4. 由于 Note.People 中需要 inverse=true ,因此无法从这一侧进行级联保存。通过填充 Note.People 集合,然后保存 Note 对象,您将获得对 Note 表的插入和对 Person 表的插入,但没有对关联表的插入。我想这就是 NHibernate 的工作方式,我还没有找到解决方法。
  5. 您只能通过在 Note 实体的 PersonNotes 集合中添加新项目来显式地级联关联表中的保存条目。

以上所有内容均通过单元测试进行了测试。您需要创建 PersonNote 类映射文件和类才能使上述工作正常进行。

如果您需要另一个类来拥有注释,比如说组织,那么您只需将另一个关联表添加到您的架构中,称为 OrgnanisationNote,并且您对组织映射文件和注释映射文件执行与上述相同的操作。

我必须再次说,这应该是任何想要完全控制他/她的多对多关联的人的最终选择。

于 2009-11-30T15:05:13.147 回答