私は、perst.net を実行するための小さな教育プロジェクトに取り組んでいます。
小さな設計上の問題があります。それは、オブジェクトの 2 つのクラス (つまり、参加者とチャンピオンシップ) の間の関係をどのように解決するのが最善かということです。参加者は多くのチャンピオンシップに参加でき、チャンピオンシップには複数の参加者がいる可能性があるため、多対多の関係です。
C# でこれを最適に行う方法を教えてください。「リレーショナル DB のような」技術クラスを使用する必要がありますか?
私は、perst.net を実行するための小さな教育プロジェクトに取り組んでいます。
小さな設計上の問題があります。それは、オブジェクトの 2 つのクラス (つまり、参加者とチャンピオンシップ) の間の関係をどのように解決するのが最善かということです。参加者は多くのチャンピオンシップに参加でき、チャンピオンシップには複数の参加者がいる可能性があるため、多対多の関係です。
C# でこれを最適に行う方法を教えてください。「リレーショナル DB のような」技術クラスを使用する必要がありますか?
オブジェクト指向 (またはドメイン駆動設計) のアプローチを探している場合、「結合」を処理する 3 番目のオブジェクトは、これを行うにはまったく間違った方法です。Add... メソッドで ILists / Enumerables を使用して、次のようにこれを処理できます。
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);
}
}
ここで重要なのは、一方の側からのみ関係を管理するようにすることです。たとえば、この場合は、チャンピオンシップ.AddParticipant() を呼び出すことによって行われます。
IEnumerable (またはその他のコレクション) プロパティを使用して、特定のアイテムに複数のアイテムを関連付けることができる関係を作成できます。あなたの例では、これは次のようになります。
class Participant {
public IEnumerable<Championship> Championships {
get {
return _championships;
}
}
private List<Championship> _championships;
}
留意すべき重要事項:
これは常に読み取り専用プロパティにしてください。これは、特に IEnumerable ではなく ICollection のような変更可能なものが返された場合に、人々を混乱させることがあります。プロパティを読み取り専用にしても、コレクションの変更は防止されませんが、リスト全体の変更は防止されます。
ロード戦略 - 上記の例では、コレクションが初期化されていないことに気付くでしょう。通常、これはコンストラクター内で、またはプロパティが最初にアクセスされたときに行います (遅延インスタンス化と呼ばれます)。プロパティ。
一般に、多対多の場合 (つまり、参加者にはチャンピオンシップ プロパティがあるが、チャンピオンシップには参加者プロパティがない、またはその逆) の場合は、他のクラスを「保持」するクラスを選択することをお勧めします。これにより、記述しなければならないコードの量が削減され、データベースの複雑さと表面積が削減されます。他の方向に呼び出しが必要な場合は、プロパティではなくメソッド呼び出しを検討してください。リレーショナルな意味での多対多は、必ずしもそれが一般的なユースケースであることを意味するわけではないことを覚えておいてください (ユーザーとして、チャンピオンシップを参加者に追加するのではなく、チャンピオンシップに参加者を追加したいだけかもしれません)。
コレクションが変更可能な場合、Save を送信すると、その下にあるコレクションが変更された場合はそれらも変更する必要があることを意味することに注意してください。これにより、かなりの複雑さが追加される可能性があります(過去に、追加/削除されたアイテムを保存するために内部リストを使用していました)
これがあなたのデザインや要件に合っているかどうかはわかりませんが、可能かもしれません...
明らかに、多対多の関係は、関係を管理する 3 番目のオブジェクトで表現するのが最も簡単です。あなたの場合、それは Championshipparticipant になります。チャンピオンシップを保持する参加者クラスにコレクションを保持するのではなく、この 3 番目のクラスのインスタンスを保持するようにします。チャンピオンシップ参加者オブジェクトは、この関係を管理します。その後、ジャンクション テーブルとして直接データベースにシリアル化できます。