2017-08-07 41 views
1

我有兩個抽象類,有兩個相應的派生類,如下所示(簡化,當然):實體框架,標誌着外鍵關係爲空,即使它是不是

public abstract class Activity 
{ 
    public int ID { get; set; } 
    public int ScheduleID { get; set; } 
    public DateTime StartTime { get; set; } 
} 

public class ProjectActivity : Activity 
{ 
} 

public abstract class Schedule 
{ 
    public int ID { get; set; } 

    protected List<Activity> _entries; 
    public List<Activity> Entries 
    { 
     get { return _entries.OrderBy(e => e.StartTime).ToList(); } 
     set { _entries = value; } 
    } 

    protected SiteSchedule() 
    { 
     _entries = new List<Activity>(); 
    } 
} 

public class ProjectSchedule : Schedule 
{ 
} 

這些類存在於數據庫使用TPH(按層次結構)構造。所以我有一個Activity表和一個Schedule表,它們都帶有一個鑑別器列。

當我試圖挽救這樣一個非常簡單的關係:

ProjectSiteSchedule schedule = new ProjectSchedule(); 

context.Schedules.Add(schedule); 
context.SaveChanges(); 

ProjectActivity activity = new ProjectActivity() 
{ 
    ScheduleID = schedule.ID, 
}; 

context.Activities.Add(activity); 
context.SaveChanges(); 

我收到以下錯誤:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

的導航屬性設置爲故意單向關係。

modelBuilder.Entity<Schedule>() 
    .HasMany(s => s.Entries) 
    .WithRequired() 
    .HasForeignKey(e => e.ScheduleID) 
    .WillCascadeOnDelete(false); 

這是一個非常奇怪的事情,因爲ScheduleID正確的ProjectActivity對象上設置:在流利的API,我定義如下的關係。但是,出於測試目的,我將ScheduleID更改爲可爲空的字段,但可以保存ProjectActivity,但在數據庫中將ScheduleID設置爲null,即使它已在代碼中設置。

看起來實體框架在嘗試保存時將ScheduleID屬性從給定的整數更改爲null值。我嘗試了this answer中給出的'骯髒的技巧'來檢查實體的狀態,然後它會嘗試保存它,但即使它作爲_entriesWithConceptualNulls條目返回實體,ScheduleID也已正確設置。

+2

你'名單 Entries'吸氣看起來麻煩......請檢查你沒有改變返回列表字段中的問題是否仍然存在。 – grek40

+0

無法用你的例子重現,你在什麼版本的EF上?另外,請在遷移後創建這些表格,因爲我在「ScheduleId」中添加並保存了一個有效值。 –

+0

@ grek40你是對的。 '.ToList()'調用導致錯誤。這很奇怪,因爲'_entries'本身就是一個列表。所以如果我通過一個沒有改變的列表一切都正常,但如果我列出這個列表,將它重新列爲一個列表並返回它,它不起作用。 – Kazu

回答

0

的問題是導航屬性Entries

protected List<Activity> _entries; 
public List<Activity> Entries 
{ 
    //don't create a new list in getter! 
    //get { return _entries.OrderBy(e => e.StartTime).ToList(); } 
    get { return _entries; } 
    set { _entries = value; } 
} 

由於吸氣返回一個新的列表(.ToList()),在_entries基礎列表不會被這種方式更新。因此,EF無法保持實體的一致狀態並引發錯誤。

將吸氣劑更改爲返回存儲的清單而不更改get { return _entries; }。如果您需要有序列表,只需在使用的代碼中添加一些getter方法或添加一個未映射的屬性以用於客戶端代碼。

[NotMapped] 
public IEnumerable<Activity> OrderedEntries 
{ 
    get { return _entries.OrderBy(e => e.StartTime); } 
}