Entity Framework (モデル優先) では、関連セット内で一致する必要がある追加の関係 (Composer) を使用して、多対多 (構成-アンソロジーなど) の関係を実装しています。
このモデルを EF で正しく作成するにはどうすればよいですか?
私は現在、2つの悪い考えを持っています:
悪い考え #1
ComposerId とローカル ID の両方を含むコンポジションおよびアンソロジー コンポジットの主キーを作成することにより、EF はこれを正しく制約します。ただし、これはすぐに問題を引き起こします。
- コンポジションとアンソロジーに関連するすべてのテーブルには、FK の ComposerId も含まれるようになりました。DBAにとっては苦痛です。
- 一意の ID などに基づいて EF 5.0 の EntitySet.Find() を使用することはできません。
悪い考え #2
デザイナで CompositionAnthology ピボット テーブルを具体化し、それに ComposerId を追加して、SQL に直接制約を追加することができました。ただし、これ:
- EF データベースの作成/更新を中断します
- エンティティのナビゲーション/追加を中断します
注: 私のデータは、実際にははるかに直感的ではない「エンゲージメント」モデルをモデル化していますが、この比喩は非常によく当てはまります。
編集: 別の図式表現で目標を達成できる可能性があるため、要求に応じて実際のモデルの一部をここに投稿しています。(簡潔にするために HashSet の割り当てを削除しました。) 論理的には、構成はこのモデルのエンゲージメントを表します。これは、承認が存在するためには、(一致するアカウントを持つ) 関連するエンゲージメントが存在する必要があるためです。
public partial class Account
{
public int Id { get; set; }
public string PrimaryEmail { get; set; }
public virtual ICollection<Endorsement> EndorsementsGiven { get; set; }
public virtual ICollection<Endorsement> EndorsementsReceived { get; set; }
public virtual ICollection<Engagement> Engagements { get; set; }
public virtual ICollection<EngagementEndorsement> EngagementEndorsements { get; set; }
}
public partial class EngagementEndorsement
{
public int Endorsement_Id { get; set; }
public int Engagement_Id { get; set; }
public int Account_Id { get; set; }
public virtual Endorsement Endorsement { get; set; }
public virtual Engagement Engagement { get; set; }
public virtual Account Account { get; set; }
}
public partial class Engagement
{
public int Id { get; set; }
public System.DateTime Start { get; set; }
public System.DateTime End { get; set; }
public string JobFunction { get; set; }
public virtual Account Account { get; set; }
public virtual ICollection<EngagementEndorsement> EngagementEndorsements { get; set; }
}
public partial class Endorsement
{
public int Id { get; set; }
public EndorsementStatus Status { get; set; }
public EndorserRole EndorserRole { get; set; }
public string Note { get; set; }
public virtual Account Endorsee { get; set; }
public virtual Account Endorser { get; set; }
public virtual ICollection<EngagementEndorsement> EngagementEndorsements { get; set; }
}
現在、「Bad Idea #2」(上記参照) を行っています。データベースが作成された後、追加の関係/制約を適用します。
-- --------------------------------------------------
-- Ensure Engagement-to-Endorsement AccountId match
-- --------------------------------------------------
ALTER TABLE [dbo].[Engagements]
ADD CONSTRAINT [UK_EngagementIdAccountId]
UNIQUE NONCLUSTERED
([Id], [Account_Id])
WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
ALTER TABLE [dbo].[EngagementEndorsements]
ADD CONSTRAINT [FK_EngagementIdAccountId]
FOREIGN KEY ([Engagement_Id], [Account_Id])
REFERENCES [dbo].[Engagements]
([Id], [Account_Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE [dbo].[Endorsements]
ADD CONSTRAINT [UK_EndorsementIdAccountId]
UNIQUE NONCLUSTERED
([Id], [Endorsee_Id])
WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
ALTER TABLE [dbo].[EngagementEndorsements]
ADD CONSTRAINT [FK_EndorsementIdAccountId]
FOREIGN KEY ([Endorsement_Id], [Account_Id])
REFERENCES [dbo].[Endorsements]
([Id], [Endorsee_Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
GO