簡體   English   中英

實體框架,代碼優先建模和循環引用

[英]Entity Framework, Code First modeling and a cyclical reference

我已經花了幾天時間,試圖解決這個問題。 在做一個簡單的項目來說明我的問題時,我偶然發現了一個可能的解決方案。 因此,這是一個雙重問題。

但首先,請提供一些背景信息:

我剛剛開始使用Entity Framework 4.1(EF)和Code First為我的ASP.NET MVC項目創建模型。 我需要一些類似的模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TestApp.Models
{
    public class Family
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Father> Fathers { get; set; }
        public virtual ICollection<Mother> Mothers { get; set; }
    }

    public class Mother
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Father
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Child
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int MotherID { get; set; }
        public int FatherID { get; set; }

        public virtual Mother Mother { get; set; }
        public virtual Father Father { get; set; }
    }
}

和DbContext:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;

namespace TestApp.Models
{
    public class TestContext : DbContext
    {
        public DbSet<Family> Families { get; set; }
        public DbSet<Mother> Mothers { get; set; }
        public DbSet<Father> Fathers { get; set; }
        public DbSet<Child> Children { get; set; }
    }
}

(請原諒這個la腳的例子,這就是我星期五的炒腦所能想到的。)

一個家庭可以有幾個母親和幾個父親。 一個孩子有一個母親和一個父親。 我與工作中的一位.NET專家進行了核對,后者同意其中沒有什么特別之處。 至少據我們所見。

但是,當我運行代碼時,出現以下異常:

System.Data.SqlServerCe.SqlCeException:引用關系將導致不允許的循環引用。 [約束名稱= Mother_Family]

我確實看到了周期: Family - Mother - Child - Father - Family 但是,如果我自己創建數據庫表(我不喜歡這樣做,那是我對Code First的喜歡),就我所知,這將是一個完全有效的數據結構。

所以,我的第一個問題是:為什么先使用代碼時會出現問題? 有沒有辦法告訴EF如何正確處理周期?

然后,正如我最初編寫的那樣,在創建一個簡單的項目來舉例說明我的問題時,我偶然發現了一個可能的解決方案。 定義模型時,我只是忘記了一些屬性。 為了清楚起見,在下面的示例中,我沒有刪除它們,而是注釋掉了我忘記的模型部分:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TestApp.Models
{
    public class Family
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Father> Fathers { get; set; }
        public virtual ICollection<Mother> Mothers { get; set; }
    }

    public class Mother
    {
        public int ID { get; set; }
        public string Name { get; set; }
        // public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Father
    {
        public int ID { get; set; }
        public string Name { get; set; }
        // public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Child
    {
        public int ID { get; set; }
        public string Name { get; set; }
        // public int MotherID { get; set; }
        // public int FatherID { get; set; }

        public virtual Mother Mother { get; set; }
        public virtual Father Father { get; set; }
    }
}

因此,刪除這些SomethingID參考屬性似乎可以解決我的問題。 正如您在本文末尾鏈接到的示例項目的控制器中所看到的那樣,我仍然可以一直循環瀏覽並執行諸如mothers.First().Family.Fathers.First().Children.First().Mother.Family.Name沒有任何問題。 但是我一直在研究的所有有關EF和Code First建模的教程和示例(例如Scott Guthrie的這篇文章 )都包含了這些屬性,因此不使用它們會讓人感到不對。

因此,我的第二個問題是:這樣做還不會發現任何弊端和問題嗎?

在此處下載示例項目: http ://blackfin.cannedtuna.org/cyclical-reference-test-app.zip,然后打開TestSolution.sln。 這些屬性在示例項目中被注釋掉。 取消注釋TestModels.cs中的行以添加屬性,從而導致循環引用異常。

注意:解決方案是創建和播種位於c:\\ TestApp.sdf的SQL CE數據庫

更新,2011年12月:我從技術上從未解決過這個問題,但是我辭掉了工作,找到了另一項不必使用Microsoft技術的工作。 那種解決了我的問題:)

在解決問題時,原為技術支持的地方是:“已提供解決方法或解決方案”。

但是,如果我自己創建數據庫表(我不喜歡這樣做,那是我對Code First的喜歡),就我所知,這將是一個完全有效的數據結構。

您應該仔細檢查這一點。 異常直接來自數據庫,而不是實體框架。 具有手動創建的具有相同約束的表結構也可能無效。 請記住,您的外鍵屬性Mother.FamilyIDFather.FamilyIDChild.MotherIDChild.FatherID 不可為空 ,因此它們表示必需的關系,並且數據庫中的相應列也不可為空。

當您從模型類中刪除所有這些屬性時,由於導航屬性可以為null因此關系突然變得可選 現在這是另一個模型,因為數據庫中的FK列可以為空! 顯然,這是允許的模型。

如果您希望模型中仍然具有表示可選關系而非必需關系的外鍵屬性,則可以使用可為空的類型: public int? FamilyID { get; set; } public int? FamilyID { get; set; } public int? FamilyID { get; set; }public int? MotherID { get; set; } public int? MotherID { get; set; } public int? MotherID { get; set; }

我遇到了幾乎相同的問題,但是我使用此答案中的建議解決了問題實體框架代碼優先-來自同一表的兩個外鍵比將鍵列的類型更改為可選更好。

這是一個已知的問題,您不是第一個遇到此問題的人。 據我所知,他們正在為即將到來的WCF版本中的更好的解決方案而努力,但是從我的經驗來看,暫時最好創建DataContracts來表示要通過網絡發送的數據,從而改變數據結構刪除循環引用。

我知道這很痛苦,但是還有其他好處,因為您很可能希望對客戶機無論如何都要使用的結構進行其他更改,而不是讓它們玩數據庫中存在的對象

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM