C#中的多对多对象关系

时间:2009-04-22 11:00:34

标签: c# .net oop object-oriented-database

我正在开展一个小型教育项目来锻炼perst.net。

我们有一个很小的设计问题,就是如何最好地解决两类对象之间的关系,即参与者锦标赛。这是一个多对多关系,因为参与者可以参加许多锦标赛锦标赛可以有多个参与者

请告知如何在C#中做到最好,我应该使用'关系数据库'技术类吗?

3 个答案:

答案 0 :(得分:9)

如果您正在寻找面向对象(或域驱动设计)方法,那么处理“连接”的第三个对象完全是错误的方法。您可以使用ILists / Enumerables和Add ...方法来处理此问题,如下所示:

public class Participant
{
    private readonly IList<Championship> _championships = new List<Championship>();

    public IEnumerable<Championship> Championships
    {
        get { return _championships; }
    }

    internal void AddChampionship(Championship championship)
    {
        if (!_championships.Contains(championship))
            _championships.Add(championship);
    }
}

public class Championship
{
    private readonly IList<Participant> _participants = new List<Participant>();

    public IEnumerable<Participant> Participants
    {
        get { return _participants; }
    }

    public void AddParticipant(Participant participant)
    {
        if (_participants.Contains(participant)) return;
        _participants.Add(participant);
        participant.AddChampionship(this);
    }
}

这里的关键是确保你只从一方管理关系 - 例如在这种情况下,可以通过调用championship.AddParticipant()

答案 1 :(得分:4)

使用IEnumerable(或其他一些集合)属性,您可以拥有任何关系,其中特定项目可以包含多个与之关联的项目。在您的示例中,这将如下所示:

class Participant {
   public IEnumerable<Championship> Championships { 
      get {
         return _championships;
      }
   }
   private List<Championship> _championships;
}

要记住一些重要的事情:

  • 始终将此设为只读属性。这有时让人感到困惑,特别是如果你有像ICollection一样可修改的东西而不是IEnumerable。将属性设置为只读不会阻止修改集合,而是修改整个列表

  • 加载策略 - 您会注意到上面的示例中的集合未被初始化。您通常在构造函数中或首次访问属性时执行此操作(称为延迟实例化) - 通常说懒惰实例化会增加一些复杂性但可以提高性能,尤其是如果不经常使用此集合或者您有很多这样的类型属性。

  • 一般来说,在多对多的情况下选择一个班级来“保持”另一个班级(即参与者拥有锦标赛属性但是锦标赛没有参赛者属性,反之亦然)。这减少了您必须编写的代码量,并降低了数据库的复杂性和表面积。如果另一个方向需要调用,请考虑方法调用而不是属性。请记住,关系意义上的多对多并不一定意味着这是常见的用例(作为用户,我可能只想将参与者添加到锦标赛而不是参加锦标赛)

  • 如果您的集合是可修改的,请记住发送保存意味着如果它们被更改,那么它下面的集合也应该被修改。这会增加很多复杂性(过去,我使用内部列表来存储添加/删除的项目)

答案 2 :(得分:1)

我不确定这是否适用于您的设计或要求,但有可能......

显然,使用管理关系的第三个对象最容易表示多对多关系。在你的情况下,它将是 championshipparticipant 。而不是在你的参与者类中拥有一个持有锦标赛的集合,反之亦然,让他们为这个第三课提供一个实例。 championshipparticipant 对象管理这种关系。然后可以将其作为联结表直接序列化到数据库。