私には、これは を接続する追加のエンティティが必要なように思えますが、それをPeriod
とClient
呼びActivity
ましょうClientActivityInPeriod
。このエンティティ (および対応するテーブル) には、3 つの外部キーと 3 つの参照があります (コレクションはありません)。その組み合わせは一意でなければならないため、そのエンティティの主キーを3つの外部キーの構成にするでしょう。次のようになります (Code-First スタイルで):
public class ClientActivityInPeriod
{
[Key, ForeignKey("Period"), Column(Order = 1)]
public int PeriodId { get; set; }
[Key, ForeignKey("Client"), Column(Order = 2)]
public int ClientId { get; set; }
[Key, ForeignKey("Activity"), Column(Order = 3)]
public int ActivityId { get; set; }
public Period Period { get; set; }
public Client Client { get; set; }
public Activity Activity { get; set; }
}
3 つの外部キーすべてが必要です(プロパティは null 許容ではないため)。
Period
、Client
およびActivity
このエンティティを参照するコレクションを持つことができます (ただし、そうする必要はありません)。たとえば、Period
次のようになります。
public class Period
{
[Key]
public int PeriodId { get; set; }
public ICollection<ClientActivityInPeriod> ClientActivities { get; set; }
}
からの外部キー、またはとの間の多対多のリンク テーブルが必要になるため、特定の期間にアクティビティがあるすべてのクライアントを含むClients
inのコレクションのようなナビゲーション プロパティを持つことはできません。外部キーまたはリンク テーブルは、クライアントにアクティビティがある場合にのみ入力されます。EF もデータベースも、このようなビジネス ロジックでは役に立ちません。これをプログラムして、アクティビティが期間に追加または削除された場合に関係が正しく更新されるようにする必要がありました。これはエラーが発生しやすく、データの一貫性を損なうリスクになります。Period
Client
Period
Client
Period
Period
1
代わりに、次のように、ナビゲーション プロパティではなくクエリによって、特定の期間にアクティビティがあるクライアントをフェッチします。
var clientsWithActivitiesInPeriod1 = context.Periods
.Where(p => p.PeriodId == 1)
.SelectMany(p => p.ClientActivities.Select(ca => ca.Client))
.Distinct()
.ToList();