English 中文(简体)
SqlDataReader 抛出 NullReferenceException!这可能是什么原因,我该如何调试?
原标题:
  • 时间:2008-12-15 00:50:09
  •  标签:

I found this in an error log and am trying to work out how it s possible. It s not every day that a NullReferenceException turns up deep within the .net base classes!

1) Exception Information
*********************************************
Exception Type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
Data: System.Collections.ListDictionaryInternal
TargetSite: Void Bind(System.Data.SqlClient.TdsParserStateObject)
HelpLink: NULL
Source: System.Data

StackTrace Information
*********************************************
   at System.Data.SqlClient.SqlDataReader.Bind(TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult esult)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet)
   at MyCode.Shared.Data.DataSocket.GetTable(String SPString)
   at <rest of stack trace>

我所能想到的唯一可能是,在同一时间有两个线程执行了同一个方法,其中一个清除或修改了传递给Fill()的DataSet。所以我的问题真正是:

  • how could this exception get thrown
  • Could a multi-thread scenario cause this exception
  • How can I be sure, eg is there a way i can step through the System.Data methods to replicate the problem?

顺便提一句,我发现了另外几个此问题的案例,一个在此线程中,另一个在某人页面的谷歌高速缓存中。但是,两者似乎都没有什么帮助。

The GetTable() method of mine that is being executed looks like this:

public DataTable GetTable(string SPString)
{
    //Setup the data objects by calling helper
    prepareDataAdaptor(SPString,CommandType.Text);

    dataAdaptor.Fill(dataSet);
    dataAdaptor.SelectCommand.Connection.Close();
    DataTable dt;
    //ensure we dispose okay
    using(dataSet)
    {   

        if(dataSet.Tables.Count==0)
        {
            dataSet.Tables.Add(new DataTable("EmptyTable"));
        }

        dt=dataSet.Tables[0];
        //because we are disposing we need to remove the table from the dataset
        dataSet.Tables.Clear();

    }
    return dt;
}

private void prepareDataAdaptor(string SPString,CommandType Type)
{
    checkForConnection();
    dataSet=new DataSet();
    dbCommand.CommandText=SPString;
    dbCommand.CommandTimeout = MySettings.CommandTimeout;
    dataAdaptor.SelectCommand=dbCommand;
    dataAdaptor.SelectCommand.CommandType=Type;
    dataAdaptor.SelectCommand.Connection=dbConnection;
    dataAdaptor.SelectCommand.Parameters.Clear();
}

dataAdaptor (sic) is an instance variable declared as an IDbDataAdapter populated with a SqlDataAdapter. dataSet is an instance variable of type DataSet.

My theory goes that thread A runs through and gets partway into the SqlDataAdapter.Fill() method. Meanwhile thread B is also executing and does something that messes up thread A, like this line:

dataAdaptor.SelectCommand.Connection.Close();

我可以看出我的这个代码不是线程安全的,但我怎么确定这是导致上述异常的问题?

many thanks for any suggestions!

罗里 (Luó lǐ)

更正:拼写很差,请忽略。我没有更新代码,因为它就是这样的。

更新:我同意这个代码存在几个需要修复的问题,但我的主要兴趣在于是否有任何方法可以验证是线程问题导致了此错误。考虑到我的应用程序,这有点牵强,但这是我所能想到的唯一事情。在我修改代码以使其更好之前,我想确定异常的原因,以便我可以确定已经修复了它。

有没有办法进入.NET代码?例如,我使用的是VS 2005 / .net 2.0,但我认为在VS 2008中,您可以查看.NET框架源代码?如果是这种情况,我是否可以创建一个2线程的场景,并通过步进来重新创建此问题?或者是否有一种不需要我安装VS 2008的方法?

最佳回答

Could a multi-thread scenario cause this exception

Instance methods of ADO.NET classes (e.g. SqlCommand) are generally not thread-safe. So if you are using such instances from multiple threads, you can expect problems such as the one you describe.

问题回答

你的数据集不应该是类级变量。在这两个调用之间或填充操作期间,它很可能被清除或被其他线程访问。

准备数据适配器(SPString,CommandType.Text);

dataAdaptor.Fill(dataSet); 這句話的中文翻譯是:dataAdaptor.Fill(dataSet);

我会在dataAdaptor.Fill(dataSet)周围添加一些日志记录代码,显示ThreadID和其他信息。您可以使用Console.Writeline,但我强烈建议使用log4net。此外,请使您的代码线程安全。每个线程应该获得自己的DataSet和DataAdapter,或使用mutex。

我猜测释放该数据集会使其包含的表无效!

顺便提一下,您不需要数据集,您可以直接填充一个数据表 - 或调用其他数据适配器函数,该函数为您创建一个数据表(我想是 Get)。

这是拼写作为"adapter"而非"adaptor";-)





相关问题
热门标签