C#中多对多对象关系

8
我正在开展一个小型教育项目,以练习perst.net。
我们有一个微小的设计问题,即如何最好地解决两个类对象之间的关系,即"参与者"和"锦标赛"。它是一个多对多的关系,因为"参与者"可以参加多个"锦标赛",而"锦标赛"也可以有多个"参与者"。
请建议在C#中如何最好地实现此功能,我应该使用"关系数据库-like"技术类吗?
3个回答

10
如果您正在寻找面向对象(或领域驱动设计)的方法,那么使用第三个对象来处理“join”完全是错误的方法。您可以使用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
很棒的答案!最后那句话非常重要...你应该将其加粗!+1 - Cerebrus

4

你可以使用IEnumerable(或其他集合)属性,使某个项目与多个项目相关联。在你的例子中,代码如下:

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

需要记住的一些重要事项:

  • 始终将此属性设置为只读。这有时会让人感到困惑,特别是如果返回的是可修改的 ICollection 而不是 IEnumerable。将属性设置为只读不会防止对集合进行修改,但可以防止对整个列表进行修改。

  • 加载策略 - 你会注意到上面的示例中集合没有被初始化。通常情况下,你可以在构造函数中或第一次访问属性时进行初始化(称为延迟实例化)- 一般来说,延迟实例化会增加一些复杂性,但可以提高性能,特别是如果该集合不经常使用或者你有很多这样的属性。

  • 通常情况下,在多对多的情况下选择一个类来“持有”另一个类是个好主意(例如:参与者具有锦标赛属性,但锦标赛没有参与者属性或反之亦然)。这样可以减少你需要编写的代码量,降低复杂度和数据库表面积。如果需要从另一个方向进行调用,请考虑使用方法调用而不是属性。请记住,从关系上看,多对多并不一定意味着这是常见的用例(作为用户,我可能只想将参与者添加到锦标赛中,而不是将锦标赛添加到参与者中)

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


1

我不确定这对你的设计或需求是否有效,但这可能是可能的...

显然,一个多对多的关系最容易用第三个对象来表示并管理关系。在你的情况下,它将是一个championshipparticipant。不要在你的参与者类中拥有一个保存冠军赛的集合,反之亦然,让它们持有对这个第三个类的实例。这个 championshipparticipant 对象管理这个关系。然后可以将它直接序列化到数据库中作为连接表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接