在使用语句

时间:2015-11-12 09:17:17

标签: c# entity-framework nullreferenceexception using-statement objectcontext

再一次吸引更多人的思想。

我遇到了一种非常奇怪的现象。正如标题所述,我在尝试创建EF ObjectContext时得到NullReferenceException,但是如果我在Using语句中创建上下文,我只会得到异常。我尝试过各种不同的方式,但总是一样。当然,这是直到昨天才能正常工作的代码。我的Windows Update在昨天早上运行可能是相关的。

总之...

如果我试试这个

using (var context = new Entities(Env.Instance.Connection))
{
    //do a bunch of EF stuff
}

我在创建ObjectContext时得到NullReferenceException。这里的Env.Instance.Connection是在程序的早期创建的EntityConnection。我已逐步确保实例和EntityConnection都存在。

如果我这样做的话

var context = new Entities(Env.Instance.Connection);
//do a bunch of EF stuff
context.Dispose();

一切正常。

我已经尝试了

using (var context = new Entities(Env.Instance.ConnectionName)) //the name of a connection string in my App.Config
{
    //do a bunch of EF stuff
}

我已经尝试了

using (var context = new Entities(Env.Instance.ConnectionString)) //the actual connection string
{
    //do a bunch of EF stuff
}

我甚至尝试过

using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
{
    //do a bunch of EF stuff
}

没关系。如果我在using语句中创建上下文,我总是会得到一个NullReferenceException。

我可以进入数据层的代码,然后退出ObjectContext构造函数

public Entities(string connectionString) : base(connectionString, "Entities")
{
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
}

但是,一旦我退出构造函数,就会抛出错误。

思想?

修改

在绝对最简单的迭代中,堆栈跟踪看起来像这样

  

at IkaPlus.ViewModel.MainVM.ProcessMail3(Object sender,   DoWorkEventArgs e)在C:\ SVN \ IkaPlus \ IkaPlus \ ViewModel \ MainVM.cs:Line   1371
     在C:\ SVN \ IkaPlus \ IkaPlus \ ViewModel \ MainVM.cs中的IkaPlus.ViewModel.MainVM.RefillQueues():第832行。

理想情况下,ProcessMail3将从BackgroundWorker调用,因此它的签名,但此刻,我从主线程调用null参数。

为了澄清,ProcessMail3方法意图从后台工作者调用,这就是为什么它的签名中有发件人和DoWorkEventArgs的原因。但此刻,我直接从主线程调用它,如下所示:ProcessMail3(null,null)

我认为rism正在发展。如果我这样做

private void RefillQueues()
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    ProcessMail3(null, null);
}

private void ProcessMail3(object sender, DoWorkEventArgs e)
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }
}

RefillQueues中的using语句有效,但ProcessMail3中的using语句不起作用。

编辑2

为了进一步简化,我删除了违规方法签名中的参数。所以,现在我打电话给

private void RefillQueues()
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    ProcessMail3();
}

private void ProcessMail3()
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }
}

相同的结果。在第一种方法中使用语句有效。在第二个方法中使用语句会抛出NullReferenceException。没有BackgroundWorkers在运行。

编辑3

所以,我似乎找到了导致我错误的原因,但我仍然无法解释。

所以,我的ProcessMail3方法实际上看起来像这样(我把它重命名为EatCookies因为......我喜欢吃饼干。)

private void EatCookies()
{
    #region Empty the Queue

    string s = "Queue 3";

    CicConnector.CreateInstance(SettingsHandler.Instance.CIC_PASSWORD,
              "MYSERVER",
              "C:\\temp");

    //Do a bunch of stuff

    #endregion

    #region EF Stuff

    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    #endregion
}

我还没有想要包含其他代码行,因为我在进入方法时已经踩过它们。 Voodoo teching,我发现如果我注释掉创建我的CiCConnector的行(不应该是相关的)我的使用声明工作正常后。如果行ISN&T已被注释掉,无论我是否实际到达该行代码,using语句都不起作用。如果我在创建字符串的行上设置断点,并跳过下一行,直接转到我的using语句,我得到NullReferenceException。如果我注释掉CiCConnector行并执行相同的操作,则using语句可以正常工作。而且,再次,如果不是使用using语句,我只是创建我的ObjectContext然后稍后手动处理它,无论CiCConnector行如何都可以正常工作。这一切都很奇怪。

编辑4

奇怪的是,CiCConnector行如果放在第一个方法中,则不会引起奇怪的行为。所以如果我这样做

private void RefillQueues()
{
    string s = "Queue 3";

    CicConnector.CreateInstance(SettingsHandler.Instance.CIC_PASSWORD,
              "MYSERVER",
              "C:\\temp");

    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    EatCookies();
}

private void EatCookies()
{
    string s = "Queue 3";

    CicConnector.CreateInstance(SettingsHandler.Instance.CIC_PASSWORD,
              "MYSERVER",
              "C:\\temp");

    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }
}

第一种方法中的using语句工作正常,但在第二种方法中它会中断。

耸肩你的猜测和我一样好。可能更好。我想我只是把它当作一个奇怪的,并且根本不使用using语句。但是,如果有人有任何见解,我会很高兴找到这里发生的事情。

1 个答案:

答案 0 :(得分:1)

EF为您管理处置,因此您可以自行使用或明确处置它

http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext.html

文章中的Snippit

  

在我与EF团队的开发者交谈之前,我的答案总是响亮的“当然!”。但是DbContext并不是这样。您不需要在DbContext对象上调用Dispose时具有宗教信仰。尽管它确实实现了IDisposable,但它只实现了它,所以你可以在某些特殊情况下调用Dispose作为安全措施。默认情况下,DbContext会自动为您管理连接。阅读到最后,听听完整的故事,看看EF开发者对此有何看法。