4

ドメインクラスがあるとします

public class Incident
{
    [Key]
    public virtual int IncidentId { get; set; }

    [Display(Name = "Parent Incident")]
    public virtual Incident ParentIncident { get; set; }

    [Display(Name = "Related Claim")]
    public virtual Incident ClaimIncident { get; set; }

 }

簡単にするために、他のプロパティは省略されています。

私がちょうどそのParentIncident場にいたとき、すべてがうまくいきました。ClaimIncidentこれで、クラスに追加されました。Entity Framework 4.3 (PreRelease)Migrationsオプションを使用してデータベースを更新しようとしていますが、EF がインシデントをインシデントにマップする方法を認識していないというエラーが表示されます。

クラスごとに 1 回だけ同じクラス インスタンスを参照できるのに、2 つ目のインスタンスを導入すると、突然参照方法がわからないのはなぜですか? モデルクラスを修正するにはどうすればよいですか?

4

1 に答える 1

3

これが起こっていると思います。ParentIncident Code First しかなかったとき、慣例により、自己参照する 1 対多の一方向の独立した関連付けの一方の端としてこれをマッピングしていました。そこには専門用語がたくさんあります。説明させてください。

  • 自己参照: 質問から明らかなように、Indicent エンティティは関係の両端にあります。
  • 1 対多: 各 Indicent には 1 つの ParentIncident があり、Incident は多くの Incident の親になることができます。
  • 単方向: インシデントからその親 (ParentIncident) へのナビゲーション プロパティはありますが、子インシデントの逆コレクション ナビゲーション プロパティはありません。
  • 独立した関連付け: クラスには外部キー プロパティがないため、EF はデータベースに FK 列 (ParentIncident_IncidentId と呼ばれる) を作成しますが、それはどのオブジェクト プロパティにもマップされません。

ここで、ClaimIncident プロパティを追加すると、Code First がマップしようとする方法が変更されます。これで、自己参照型の 1 対 1 の双方向 FK アソシエーションが作成されます。

  • インシデントからインシデントへの 2 つのナビゲーション プロパティを見て、これらが同じ関係の 2 つの側面であると想定するため、1 対 1 です。どちらもコレクション プロパティではないため、関係は 1 対 1 です。
  • リレーションシップの両端に nvaigation プロパティがあるため、再び双方向になります。
  • FK は、1 対 1 の関係が PK から PK になり、FK (PK である) がマップされるため、EF は常にこれを FK 関係として扱うためです。

しかし、Code First は、この 1 対 1 の関係のどちら側がプリンシパル エンドで、どちらが従属エンドであるかを判断できません。そして、これは時々問題になります...そのため、Code Firstがスローします。

では、スレッドとモデルから、ここでは 1 対 1 の関係が必要ないことがわかります。(1 対 1 の自己参照 PK と PK の関係は無意味なので、Code First で作成すべきではないと主張することもできますが、Code First はそれほどスマートではありません。)

FK を挿入すると、2 つのことが起こります。まず、Code First は、これらが再び 1 対多の関係である必要があると想定しています。次に、Code First に FK プロパティの名前が付けられ、その名前を使用してデータベース内の FK 列に名前が付けられます。しかし、その名前は、独立した関連付けに対して既に作成されている FK 列と同じではありません。つまり、ParentIncident_IncidentId ではありません。つまり、移行ではこの列を削除して新しい列を作成する必要があり、データが失われます。

Code First に、2 つの自己参照型、単方向、1 対多、独立した関連付けが本当に必要であることを伝えるには、次の流暢なマッピングを使用します。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Incident>()
        .HasOptional(e => e.ParentIncident)
        .WithMany();

    modelBuilder.Entity<Incident>()
        .HasOptional(e => e.ClaimIncident)
        .WithMany();
}

これで、移行によってデータベースが正しく更新されるはずです。ここで、FK 関連付けへの変更を検討する必要があるかもしれないと言わなければなりません。その場合、移行で何らかのデータ モーションを実行するか、データ損失がある場合はそのまま受け入れるか、Code First に FK を使用し続けるように指示する必要があります。以前に生成した列名。

于 2012-03-14T06:07:21.690 に答える