我正在开展一个小型教育项目来锻炼perst.net。
我们有一个很小的设计问题,就是如何最好地解决两类对象之间的关系,即参与者和锦标赛。这是一个多对多关系,因为参与者可以参加许多锦标赛和锦标赛可以有多个参与者
请告知如何在C#中做到最好,我应该使用'关系数据库'技术类吗?
答案 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 对象管理这种关系。然后可以将其作为联结表直接序列化到数据库。