Entity Framework Code First 在内部使用虚拟 属性,调用时为空引用
Entity Framework Code First using virtual property internally, null reference when called
我对 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; }
}
有上下文 class:
public class MyDBContext : DbContext
{
public DbSet<RemoteEnvironment> RemoteEnvironments { get; set; }
public DbSet<RemoteService> RemoteServices { get; set; }
}
此模型在创建数据库和播种时运行良好。 RemoteService
class 还包含此 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
是空的。
从调试中我了解到,当我从 context.RemoteServices
中获取 service
时,它会获取所有属性。首先 Name
,然后 MachineName
,跳过 RunningAt
(为什么?延迟加载?) 然后尝试获取 Version
,但是由于RunningAt
为空,不能。
我尝试使用
定义RunningAt
获取和设置方法
private RemoteEnvironment _runningAt
但问题依然存在,从数据库中获取数据时,RunningAt
和 _runningAt
均为 null。
似乎我需要以某种方式在 Version
的获取中从数据库加载对 RemoteEnvironment
的引用。但是在这里创建上下文似乎有点多。
我还能做什么?我真的很想保持 Version
不变。如果无法完成,我将不得不制定解决方法。单独检查版本,主动获取和设置它。
编辑 1:
我现在已经尝试了三种不同的方法来 "pre-load" RemoteEnvironments
.
第一个:
"Pre-loading" 通过从数据库中获取所有 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);
}
}
由于 RunningAt 为空,仍然出现 NullReferenceException。
第二个:
删除虚拟关键字。
[ForeignKey("MachineName")]
public RemoteEnvironment RunningAt { get; set; } // virtual keyword removed
由于 RunningAt 为空,仍然出现 NullReferenceException。
第三个:
使用 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);
}
}
由于 RunningAt 为空,仍然出现 NullReferenceException。
我什至尝试了以上的所有组合,包括同时使用所有三种。 仍然收到 NullReferenceException,因为 RunningAt 为空。
我也试过走另一条路,通过 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
和随后调用 Version
之前加载 RemoteEnvironments
时也不行。
我想做的事情似乎不可能。核心问题是有一个导航属性然后在另一个属性中引用它'获取或设置方法。这似乎不起作用。我尝试关闭延迟加载,强制加载 Include
并预加载导航 属性 指向的 DbSet。在每一种情况下,导航 属性 引用,在我的例子中 RunningAt
,在另一个 属性 的 get/set 方法中都是空的。
Entity Framework 似乎不支持在另一个 属性 中引用导航 属性。如果有人知道,请告诉我如何。同时,这将是公认的答案。
我对 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; }
}
有上下文 class:
public class MyDBContext : DbContext
{
public DbSet<RemoteEnvironment> RemoteEnvironments { get; set; }
public DbSet<RemoteService> RemoteServices { get; set; }
}
此模型在创建数据库和播种时运行良好。 RemoteService
class 还包含此 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
是空的。
从调试中我了解到,当我从 context.RemoteServices
中获取 service
时,它会获取所有属性。首先 Name
,然后 MachineName
,跳过 RunningAt
(为什么?延迟加载?) 然后尝试获取 Version
,但是由于RunningAt
为空,不能。
我尝试使用
定义RunningAt
获取和设置方法
private RemoteEnvironment _runningAt
但问题依然存在,从数据库中获取数据时,RunningAt
和 _runningAt
均为 null。
似乎我需要以某种方式在 Version
的获取中从数据库加载对 RemoteEnvironment
的引用。但是在这里创建上下文似乎有点多。
我还能做什么?我真的很想保持 Version
不变。如果无法完成,我将不得不制定解决方法。单独检查版本,主动获取和设置它。
编辑 1:
我现在已经尝试了三种不同的方法来 "pre-load" RemoteEnvironments
.
第一个:
"Pre-loading" 通过从数据库中获取所有 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);
}
}
由于 RunningAt 为空,仍然出现 NullReferenceException。
第二个: 删除虚拟关键字。
[ForeignKey("MachineName")]
public RemoteEnvironment RunningAt { get; set; } // virtual keyword removed
由于 RunningAt 为空,仍然出现 NullReferenceException。
第三个:
使用 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);
}
}
由于 RunningAt 为空,仍然出现 NullReferenceException。
我什至尝试了以上的所有组合,包括同时使用所有三种。 仍然收到 NullReferenceException,因为 RunningAt 为空。
我也试过走另一条路,通过 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
和随后调用 Version
之前加载 RemoteEnvironments
时也不行。
我想做的事情似乎不可能。核心问题是有一个导航属性然后在另一个属性中引用它'获取或设置方法。这似乎不起作用。我尝试关闭延迟加载,强制加载 Include
并预加载导航 属性 指向的 DbSet。在每一种情况下,导航 属性 引用,在我的例子中 RunningAt
,在另一个 属性 的 get/set 方法中都是空的。
Entity Framework 似乎不支持在另一个 属性 中引用导航 属性。如果有人知道,请告诉我如何。同时,这将是公认的答案。