2011-04-04 64 views
86

我一直在尋找關於如何使用代碼優先EF 4.1來聲明外鍵關係和其他約束的資源,但沒有多少運氣。基本上我在代碼中構建數據模型並使用MVC3來查詢該模型。一切工作通過MVC這是偉大的(微軟的榮譽!),但現在我希望它不工作,因爲我需要有數據模型約束。如何聲明外鍵關係在MVC3中使用代碼優先實體框架(4.1)?

例如,我有一個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; } 
} 

這是錯誤我現在得到當訪問VS生成視圖病人:

錯誤信息

的ForeignKeyAttribute物業 「 'PhysicianPortal.Models.Order'不是 有效。在依賴類型 'PhysicianPortal.Models.Order'上找不到外鍵名'Parent' 。 名稱值應該以逗號分隔 外鍵屬性名稱的列表。

問候,

圭多

回答

146

如果你有一個Order類,添加引用模型中的另一個類,例如Customer屬性應該足以讓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的屬性以將其用作外鍵實施者。你可以做兩件事情:

1)拆下ForeignKeyAttribute並用RequiredAttribute更換標記的關係的要求:

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

裝飾與RequiredAttribute一個屬性也有一個很好的副作用:關係在數據庫中使用ON DELETE CASCADE創建。

我還建議讓物業virtual啓用延遲加載。

2)創建一個名爲Parent的屬性,該屬性將用作外鍵。在它可能更有意義叫它例如ParentID這種情況下,(你需要在ForeignKeyAttribute改名字爲好):

public int ParentID { get; set; } 

在我的經驗,在這種情況下,雖然它的工作原理最好有它周圍的其他方法:

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

public virtual Patient Patient { get; set; } 
+0

謝謝Sergi - 我在塊引用中添加了一些額外的信息。 – 2011-04-04 21:40:28

+0

@Guido - 我已根據您的最新代碼編輯更新了我的答案,希望這有助於您。 – 2011-04-05 07:13:06

+1

幹得好! – Shimmy 2012-12-04 01:37:30

27

您可以定義外鍵:

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屬性名稱不包含您必須使用ForeignKeyAttribute數據註釋或流暢API映射關係

數據註解的導航屬性名和父名PK的:

// 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); 

其他類型的限制可由data annotations and model validation強制實施。

編輯:

,如果你不設置ParentId你會得到一個異常。它是必需的財產(不可爲空)。如果你只是不設置它,它很可能會嘗試將默認值發送到數據庫。默認值爲0,所以如果你沒有Id = 0的客戶,你會得到一個異常。

+0

謝謝拉迪斯拉夫 - 我在塊引用中添加了一些額外的信息。 – 2011-04-04 21:41:59

+0

@Guido:編輯我的答案。 – 2011-04-04 21:48:51

+0

@拉迪斯拉夫。所以爲了強制執行這個約束,我必須同時引用Parent和對ParentId的引用。那是對的嗎?我將添加上面的實際類以供參考。 – 2011-04-04 22:04:07

相關問題