5

当这种关系本身具有属性时,如何将一个类映射到同一类的其他实例?

我有一个名为 Person 的类,它映射到一个表 Person

PersonID   PersonName    PersonAge 
----------------------------------
       1   Dave Dee             55
       2   Dozy                 52
       3   Beaky                45
       4   Mick                 55
       5   Tich                 58

我希望使用名为 PersonPerson 的连接表在 Person 和 Person 之间建立多对多关系:

 PersonPersonID  PersonID  RelatedPersonID RelationshipID 
 --------------------------------------------------------
              1         1                5              1
              2         3                4              2
              3         2                1              3

我想要 PersonPerson 表中的以下属性:

RelationshipID  RelationshipName
--------------------------------
             1  Colleague
             2  Manager
             3  Tutor

这个问题和Billy McCafferty的链接到帖子解释说,由于 PersonPerson 表中的附加列,必须将 PersonPerson 关系从正常的 JOIN 提升到其自身的实体。但是,它没有解释当它是自加入时要做什么。不同之处在于,如果我要求所有与Dave Dee (ID = 1) 相关的人,我不仅应该得到Tich (ID = 5),而且我也应该得到Dozy (ID = 2),因为 Dave Dee也在 RelatedPersonID 列中。

到目前为止,我的解决方案是在我的 Person 类中有两个属性。

public virtual IList<PersonPerson> PersonPersonForward {get;set;}
public virtual IList<PersonPerson> PersonPersonBack {get;set;}

private List<PersonPerson> personPersonAll;
public virtual List<PersonPerson> PersonPersonAll 
{
   get
   {
       personPersonAll = new List<PersonPerson>(PersonPersonForward);
       personPersonAll.AddRange(PersonPersonBack);
       return personPersonAll;
   }
}

并在 hbm 中有以下内容:

 <bag name="PersonPersonForward" table="PersonPerson" cascade="all">
      <key column="PersonID"/>
      <one-to-many class="PersonPerson" />
 </bag>

 <bag name="PersonPersonBack" table="PersonPerson" cascade="all">
      <key column="RelatedPersonID"/>
      <one-to-many class="PersonPerson" />
 </bag>

这似乎有点笨拙和不雅。NHibernate 通常对大多数日常问题都有优雅的解决方案。以上是明智的做法还是有更好的方法?

4

2 回答 2

2

我想我也会这样做,但是,我认为这样建模有点“笨拙”。我的意思是:你有一个与某个人相关的人的集合,但你也有一个“反向关系”。
这真的有必要吗?是否可以选择删除此回溯集合,而是在 PersonRepository 上指定一个方法,该方法可以将所有与给定人员有某种关系的人返回给您?

嗯,这听起来可能有点晦涩难懂,所以这里有一些代码(请注意,为了简洁起见,我省略了“虚拟”修饰符等......(我也不想有这些修饰符,所以在 99 % 的时间,我在我的类映射中指定“lazy=false”)。

public class Person
{
    public int Id {get; set;}
    public string Name {get; set;}

    public IList<PersonPerson> _relatedPersons;

    public ReadOnlyCollection<PersonPerson> RelatedPersons
    {
        get
        {
           // The RelatedPersons property is mapped with NHibernate, but
           // using its backed field _relatedPersons (can be done using the 
           // access attrib in the HBM.
           // I prefer to expose the collection itself as a readonlycollection
           // to the client, so that RelatedPersons have to be added through
           // the AddRelatedPerson method (and removed via a RemoveRelatedPerson method).

           return new List<PersonPerson) (_relatedPersons).AsReadOnly();
        }
    }

    public void AddRelatedPerson( Person p, RelationType relatesAs )
    {
       ...
    }

}

如您所见,Person 类只剩下一个集合,即表示此 Person 所具有的关系的 PersonPerson 对象的集合。为了获取与给定 Person 有关系的 Person,您可以在 PersonRepository 上创建一个返回这些 Person 的特定方法,而不是将它们放在 Person 类的集合中。我认为这也会提高性能。

public class NHPersonRepository : IPersonRepository
{
    ...

    public IList<Person> FindPersonsThatHaveARelationShipWithPerson( Person p )
    {
        ICriteria crit = _session.CreateCriteria <Person>();

        crit.AddAlias ("RelatedPersons", "r");

        crit.Add (Expression.Eq ("r.RelatedWithPerson", p));

        return crit.List();

    }
}

“反向引用”不是 Person 类的成员;它必须通过存储库访问。这也是 Eric Evans 在他的 DDD 书中所说的:在某些情况下,最好在存储库中有一个专门的方法可以让您访问相关对象,而不是让它们(= 相关对象)随身携带与对象本身。

我没有测试代码,我只是在这里输入了它,所以我也没有检查语法错误等......但我认为它应该澄清一下我会如何看待这个。

于 2009-03-06T08:20:11.237 回答
2

在我看来,您实际上已经构建了有向图的模型,并且这两个映射PersonPersonForward分别PersonPersonBack表示传出和传入边。

您的关系类型的语义强化了这种定向性:虽然is-a-Colleague-of很可能是对称关系,但is-a-Manager-ofis-a-Tutor-of几乎肯定是不对称的。

我认为在这种情况下,数据模型试图告诉您,这两个链接集合虽然是兼容类型,但在上下文中并不是一回事。

于 2009-03-06T08:37:22.367 回答