为什么在重构代码后我得到“对象引用未设置为对象的实例”?

时间:2011-05-30 16:44:14

标签: asp.net-mvc-3 entity-framework-4.1

我有一个包含几列的表格,其中一列是“所有者”的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,但是当我执行SelectCompany()并检查EmailTemplate时,EmailTemplate.CompanyID被设置为正确的值,尽管此方法仅填充{{ 1}}对象,不接触任何其他东西。

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

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

当数据库具有正确的ID时,我无法弄清楚为什么它是空的。

在运行_Company之后,我无法弄清楚为什么它在第一个示例中获得了正确的值。

最重要的是,我需要做些什么来解决它?我猜我在某个地方搞砸了,但我只是看不到它。

2 个答案:

答案 0 :(得分:1)

  

我无法弄清楚为什么它是空的   从数据库开始时开始   正确的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();

或启用延迟加载。

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

答案 1 :(得分:0)

SelectCompany必须运行一些填充CompanyID的代码。我的猜测是你正在使用延迟加载的ORM而SelectCompany会导致CompanyID被填充。