asp.net MVC 3 - 为什么重构代码后会出现"Object reference not set to an instance of an object"?



我有一个表,它有几列,其中一列是"所有者"的FK ID。

在我的删除声明中,我有以下代码:

public ActionResult DeleteEmailTemplate(int id = 0)
{
    EmailTemplate EmailTemplate = db.EmailTemplates.Find(id);
    Company _Company = SelectCompany();
    if (_Company.id != EmailTemplate.CompanyID.id)
        return Content("Security Error");
    return Content("Passed... Do Delete stuff");
 }

这很好,但是,我需要在很多地方这样做,所以我尝试提取方法,现在我有了:

public ActionResult DeleteEmailTemplate(int id = 0)
{
    EmailTemplate EmailTemplate = db.EmailTemplates.Find(id);
    if (!SecurityCheck(EmailTemplate.CompanyID.id))
         return Content("Security Fail");
    return Content("Passed... Do Delete stuff");    
}

我认为SecurityCheck的代码不相关,因为我一直在设置断点,我知道错误是因为当调用SecurityCheck时,EmailTemplate.CompanyID为Null,但。。。我不明白为什么它是空的。

在第一个示例中,它是Null,但当我执行SelectCompany()并检查EmailTemplate时,EmailTemplate.CompanyID被设置为正确的值,尽管此方法只填充_Company对象,不涉及任何其他内容。

在第二个示例中,它再次为Null,但保持为Null。

所以,问题是我需要帮助:

当数据库有正确的ID时,我不明白为什么一开始它是空的。

我不明白为什么在运行SelectCompany()之后,它在第一个示例中得到了正确的值。

最重要的是,我需要做些什么来修复它?,我猜我在某个大地方搞砸了,但我就是看不出来。

我不明白为什么对从数据库具有正确的ID。

这行。。。

EmailTemplate EmailTemplate = db.EmailTemplates.Find(id);

永远不会加载导航属性(在您的情况下为CompanyID)。导航属性仅被热切加载(使用Include)、显式加载或延迟加载。您似乎没有启用延迟加载,否则访问CompanyID应该会自动加载属性。而且你没有利用其他两个选项。

我不明白为什么第一个示例中的正确值在运行SelectCompany()之后。

可能是因为关系跨度。当您在SelectCompany方法中将公司加载到上下文中时,Entity Framework会自动修复已加载的其他对象中的引用。因此EmailTemplate.CompanyID会自动填充。

最重要的是,我需要什么该怎么办?,

使用上面提到的三个选项之一:

热切装载(一次往返):

EmailTemplate EmailTemplate = db.EmailTemplates.Include(e => e.CompanyID)
    .Where(e => e.ID == id).SingleOrDefault();

显式装载(两次往返):

EmailTemplate EmailTemplate = db.EmailTemplates.Find(id);
db.Entry(EmailTemplate).Reference(e => e.CompanyID).Load();

或者启用延迟加载。

(在您的特殊情况下,我更喜欢快速加载。)

SelectCompany必须执行一些填充CompanyID的代码。我的猜测是,您使用的是带有延迟加载的ORM,SelectCompany会导致CompanyID被填充。

相关内容

  • 没有找到相关文章

最新更新