针对特定场景(一对多/一对一)更正NHibernate映射

时间:2009-10-20 11:44:12

标签: nhibernate one-to-many one-to-one many-to-one

我有以下结构:

User has many books in his history

被翻译成以下

class User { ICollection<Book> History }       // C#
User -> UserHistory (UserId, BookId) -> Book   // DB

现在我想在历史记录中添加日期,创建以下类结构:

class User { ICollection<Read> History }
class Read { Book Book, Date At }

并保持db模式几乎不变

User -> UserHistory (UserId, BookId, At) -> Book

我想将Read映射到UserHistory,问题是:

  1. id的映射中,我应该将Read用作什么? UserHistory主键为(UserId, BookId)。我需要id NH来工作吗?
  2. UserHistory -> Book似乎属于one-to-one。 在这种情况下,如何在BookId中指定UserHistory列名称? 我在one-to-one上没有看到列属性(并且我有理由明确列名称。)

2 个答案:

答案 0 :(得分:2)

在您的第一个场景中,UserHistory只是一个多对多关系的映射表,并且没有正确的对象。现在,UserHistory表/ Read类是一个单独的实体,因此需要某种标识符。最简单的方法是将主键ReadId(或UserHistoryId)添加到UserHistory表。

您不必添加单独的密钥,并且可以在UserId和BookId上使用复合密钥 - 但用户是否可以多次读取图书?假设是这样,那么您还需要将At列添加到组合键以使其唯一。这很丑陋,在处理集合时会导致其他问题,所以不值得。

UserHistory to Book关系实际上是多对一而不是一对一。许多不同的用户可以阅读同一本书(也许同一个用户可以多次阅读一本书)。将多对一视为对象参考。

答案 1 :(得分:1)

问题1:不,你不需要id,你可以将它映射为组件(或者在这种情况下是复合元素,它在列表中)

问题2:用户历史记录 - &gt;本书不是一对一的,许多用户可能会随着时间的推移阅读同一本书,因此它是多对一的,应该如此映射。

可能不完整的映射如下所示:

<class name="User">

  <bag name="History" table="UserHistory">
    <key name="UserId">
    <composite-element class="Read">
      <property name="At" />
      <many-to-one name="Book" column="BookId" />
    </composite-element>
  </bag>

注意:忘记one-to-one映射。当你有两个共享相同主键的表并且这种方式真正一对一地链接在一起时,很少使用它。在大多数情况下,您需要many-to-one,即使在现实世界中它实际上是一对一的。