MVC3のコードファーストエンティティフレームワーク(4.1)を使用して外部キーの関係を宣言するにはどうすればよいですか?


104

私は多くの運がなくてもコードファーストEF 4.1を使用して外部キー関係と他の制約を宣言する方法に関するリソースを探していました。基本的に私はコードでデータモデルを構築し、MVC3を使用してそのモデルをクエリしています。すべてが素晴らしいMVCを介して機能します(Microsoftに対してkudos!)。

たとえば、外部オブジェクト(テーブル)である大量のプロパティを持つOrderオブジェクトがあります。現在、問題なく注文を作成できますが、外部キーや外部オブジェクトを追加することはできません。MVC3はこれを問題なく設定します。

保存する前に自分でオブジェクトをコントローラークラスに追加するだけでよいことに気づきましたが、制約関係が満たされていない場合にDbContext.SaveChanges()の呼び出しを失敗させたいと思います。

新情報

したがって、具体的には、顧客オブジェクトを指定せずにOrderオブジェクトを保存しようとしたときに例外が発生するようにしたいと思います。ほとんどのCode First EFドキュメントで説明されているようにオブジェクトを作成しただけでは、これは動作ではないようです。

最新のコード:

public class Order
{
    public int Id { get; set; }

    [ForeignKey( "Parent" )]
    public Patient Patient { get; set; }

    [ForeignKey("CertificationPeriod")]
    public CertificationPeriod CertificationPeriod { get; set; }

    [ForeignKey("Agency")]
    public Agency Agency { get; set; }

    [ForeignKey("Diagnosis")]
    public Diagnosis PrimaryDiagnosis { get; set; }

    [ForeignKey("OrderApprovalStatus")]
    public OrderApprovalStatus ApprovalStatus { get; set; }

    [ForeignKey("User")]
    public User User { get; set; }

    [ForeignKey("User")]
    public User Submitter { get; set; }

    public DateTime ApprovalDate { get; set; }
    public DateTime SubmittedDate { get; set; }
    public Boolean IsDeprecated { get; set; }
}

これは、PatientのVSで生成されたビューにアクセスするときに発生するエラーです。

エラーメッセージ

タイプ 'PhysicianPortal.Models.Order'のプロパティ 'Patient'のForeignKeyAttributeは無効です。外部キー名「親」は、依存型「PhysicianPortal.Models.Order」で見つかりませんでした。Name値は、外部キープロパティ名のコンマ区切りのリストである必要があります。

よろしく、

グイド

回答:


164

Orderクラスがある場合は、たとえばモデル内の別のクラスを参照するプロパティを追加するCustomerだけで、EFに関係があることをEFに通知できます。

public class Order
{
    public int ID { get; set; }

    // Some other properties

    // Foreign key to customer
    public virtual Customer Customer { get; set; }
}

FK関係は常に明示的に設定できます。

public class Order
{
    public int ID { get; set; }

    // Some other properties

    // Foreign key to customer
    [ForeignKey("Customer")]
    public string CustomerID { get; set; }
    public virtual Customer Customer { get; set; }
}

ForeignKeyAttributeコンストラクタは、パラメータとして文字列を取ります:あなたは外部キープロパティの上に置いた場合、それは、関連するナビゲーションプロパティの名前を表します。ナビゲーションプロパティに配置すると、関連付けられた外部キーの名前を表します。

あなたがどこに配置する場合はこれが意味することは、あるForeignKeyAttributeCustomerプロパティ、属性がかかるだろうCustomerIDコンストラクタで:

public string CustomerID { get; set; }
[ForeignKey("CustomerID")]
public virtual Customer Customer { get; set; }

最新のコードに基づいた編集 次の行が原因でエラーが発生します。

[ForeignKey("Parent")]
public Patient Patient { get; set; }

EFはParent、外部キーエンフォーサーとして使用するために呼び出されるプロパティを探します。次の2つのことができます。

1)を削除してForeignKeyAttributeに置き換えRequiredAttribute、関係を必要に応じてマークします。

[Required]
public virtual Patient Patient { get; set; }

プロパティをで装飾すると、RequiredAttribute良い副作用がありますON DELETE CASCADE。データベース内のリレーションはで作成されます。

またvirtual、遅延読み込みを有効にするプロパティを作成することをお勧めします。

2)Parent外部キーとして機能するというプロパティを作成します。その場合、たとえばそれを呼び出すことはおそらくより理にかなっていますParentIDForeignKeyAttribute同様に名前を変更する必要があります):

public int ParentID { get; set; }

この場合の私の経験では、それを逆にする方がうまくいきます:

[ForeignKey("Patient")]
public int ParentID { get; set; }

public virtual Patient Patient { get; set; }

ありがとうSergi-ブロックの見積もりにいくつかの追加情報を追加しました。
グイドアンセルミ2011

@Guido-私はあなたの最新のコード編集に基づいて私の答えを更新しました、これが役に立てば幸いです。
Sergi Papaseit

30

次の方法で外部キーを定義できます。

public class Parent
{
   public int Id { get; set; }
   public virtual ICollection<Child> Childs { get; set; }
}

public class Child
{
   public int Id { get; set; }
   // This will be recognized as FK by NavigationPropertyNameForeignKeyDiscoveryConvention
   public int ParentId { get; set; } 
   public virtual Parent Parent { get; set; }
}

現在、ParentIdは外部キープロパティであり、子と既存の親の間に必要な関係を定義しています。親を存在させずに子を保存すると、例外がスローされます。

FKプロパティ名がナビゲーションプロパティ名と親PK名で構成されていない場合は、ForeignKeyAttributeデータアノテーションまたはFluent APIを使用して関係をマッピングする必要があります

データ注釈:

// The name of related navigation property
[ForeignKey("Parent")]
public int ParentId { get; set; }

Fluent API:

modelBuilder.Entity<Child>()
            .HasRequired(c => c.Parent)
            .WithMany(p => p.Childs)
            .HasForeignKey(c => c.ParentId);

他のタイプの制約は、データ注釈とモデル検証によって適用できます。

編集:

設定しない場合、例外が発生しますParentId。これは必須プロパティです(null可能ではありません)。単に設定しない場合、おそらくデフォルト値をデータベースに送信しようとします。デフォルト値は0なので、Id = 0の顧客がいない場合は例外が発生します。


Ladislav氏に感謝します。ブロック引用にいくつかの追加情報を追加しました。
グイドアンセルミ

@Ladislav。したがって、この制約を適用するには、Parentへの参照とParentIdへの参照の両方が必要です。あれは正しいですか?上記の実際のクラスを参照用に追加します。
グイドアンセルミ2011

@ガイド:それは新しい情報です。外部キープロパティを使用していません。すべてのナビゲーションプロパティは、デフォルトでオプションとして処理されます。流暢なマッピングを使用して、必要に応じてそれらをマッピングします。
Ladislav Mrnka、2011

@Ladislav:ありがとうございます。データアノテーションとFluent APIの違いを理解するために周りを見回しています。上記のコードに、あなたの言っているとおりの変更を加えました。以上でいいですか?よろしく。
グイドアンセルミ2011

ForeignKey属性は、外部キープロパティに関連するナビゲーションプロパティを定義しません(またはその逆)。外部キープロパティがないため、その属性を使用できません。ナビゲーションプロパティでRequired属性を使用してみてください(テストしていません)。
Ladislav Mrnka、2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.