0

我對Entity Framework完全陌生。我創建了一個模型來觀看遠程機器上的服務。目前看起來是這樣的:實體框架代碼首先在內部使用虛擬屬性,當調用時爲空引用

注意:我已盡力使用可理解的通用名稱,因爲這是來自企業環境。

public class RemoteService 
{ 
    [Key, Column(Order = 0)] 
    public string Name { get; set; } 

    [Key, Column(Order = 1)] 
    public string MachineName { get; set; } 

    [ForeignKey("MachineName")] 
    public virtual RemoteEnvironment RunningAt { get; set; } 
} 

public class RemoteEnvironment 
{ 
    [Key] 
    public string MachineName { get; set; } 

    public string Configuration { get; set; } 

    public string EnvironmentNr { get; set; } 

    public virtual ICollection<RemoteService> Services { get; set; } 
} 

隨着上下文類:創建數據庫和它播種時

public class MyDBContext : DbContext 
{ 
    public DbSet<RemoteEnvironment> RemoteEnvironments { get; set; } 
    public DbSet<RemoteService> RemoteServices { get; set; } 
} 

這個優良樣板工程。 RemoteService類還包含此Version屬性,以從Octopus Deploy API獲取版本。

private string _version = "N/A"; 
public string Version 
{ 
    get 
    { 
     var item = GetItemFromOctopus(Name, RunningAt.EnvironmentNr); 
     if (item != null) 
     { 
      _version = item.ReleaseVersion; 
     } 
     return _version; 
    } 
    set 
    { 
    } 
} 

這也適用於創建和種子數據庫。我試圖從數據庫中獲取數據時出現我的問題。事情是這樣的:

using (MyDBContext context = new MyDBContext()) 
{ 
    var serviceNames = new List<string>(); 
    foreach (RemoteService service in context.RemoteServices) 
    { 
     serviceNames.Add(service.Name); 
    } 
} 

在執行上面的代碼中,我得到一個NullReferenceException,因爲RunningAt爲空。 NullReference

調試從我收集,這是當我搶servicecontext.RemoteServices,它獲取的所有屬性。首先Name,然後MachineName,跳過RunningAt(爲什麼?懶加載?)然後試圖得到Version,但由於RunningAt爲空,它不能。

我試圖定義RunningAt get和使用

private RemoteEnvironment _runningAt 

設置方法,但問題保持不變,兩者RunningAt_runningAt都爲空,而從數據庫中提取數據。

看來我不知何故需要從Version的數據庫中加載對RemoteEnvironment的引用。但是,在這裏創建一個上下文似乎有點多。

我還能做什麼?我真的想保持Version原樣。如果無法完成,我將不得不採取一種解決方法。單獨檢查版本,反而積極獲取並設置它。

編輯1: 我現在已經嘗試了三種不同的方式爲「預加載」的RemoteEnvironments

第一張: 從數據庫中獲取所有RemoteEnvironments的「預加載」。

using (MyDBContext context = new MyDBContext()) 
{ 
    var serviceNames = new List<string>(); 
    List<M3BEnvironment> activateEnv = db.M3BEnvvironments.ToList(); //added line 
    foreach (RemoteService service in context.RemoteServices) 
    { 
     serviceNames.Add(service.Name); 
    } 
} 

仍然得到NullReferenceException,因爲RunningAt爲null。

第二個: 刪除虛擬關鍵字。

[ForeignKey("MachineName")] 
public RemoteEnvironment RunningAt { get; set; } // virtual keyword removed 

仍然收到NullReferenceException,因爲RunningAt爲空。

第三: 使用Include強制加載。

using (MyDBContext context = new MyDBContext()) 
{ 
    var serviceNames = new List<string>(); 
    var services = context.RemoteServices.Include(s => s.RunningAt).ToList(); 
    foreach (RemoteService service in services) 
    { 
     serviceNames.Add(service.Name); 
    } 
} 

仍然得到NullReferenceException,因爲RunningAt爲null。

我甚至嘗試了上述的所有組合,包括所有三個在同一時間。 由於RunningAt爲null,所以仍然得到NullReferenceException。

我也試着走另一條路,通過RemoteEnvironments和包括Services

using (MyDBContext context = new MyDBContext()) 
{ 
    var environments = context.RemoteEnvironments.Include(env => env.Services).ToList(); // NullRefereceException happens at this call 
    var serviceNames = new List<string>(); 
    var services = context.RemoteServices.Include(s => s.RunningAt).ToList(); 
    foreach (RemoteService service in services) 
    { 
     serviceNames.Add(service.Name); 
    } 
} 

仍然得到的NullReferenceException因爲RunningAt爲空。只有這一次它發生,而environments電話試圖包括他們。

我想要做的事似乎不可能。使用Version屬性中引用的RunningAt屬性,因爲它永遠不會從數據庫加載。即使我強迫它在呼叫RemoteService之前加載RemoteEnvironments,並隨後呼叫Version

+0

因爲'RunningAt'在'context.RemoteEnvironments'而不是'context.RemoteServices'你試圖從中獲得它我猜 – jamiedanq

+0

@jamiedanq嗯,是的。這是當前的問題。我希望能夠在'Version'屬性中引用它。最好不必創建新的數據庫引用。我考慮的越多,就越傾向於尋找解決方法。 – Skillzore

+0

爲什麼不在獲取版本之前先從數據庫中獲取所有'RemoteEnvironments'? – jamiedanq

回答

0

我想要做的似乎不可能。核心問題是有一個導航屬性,然後在另一個屬性的get或set方法中引用它。這似乎並不奏效。我嘗試關閉延遲加載,強制加載Include,並且還預載了導航屬性指向的DbSet。在每種情況下,導航屬性引用(在我的示例中爲RunningAt)在其他屬性的get/set方法內都爲null。

實體框架似乎不支持在另一個屬性內引用導航屬性。如果有人知道,否則請告訴我如何。與此同時,這將是公認的答案。

相關問題