2008-12-15 97 views
2

我在一个错误日志中发现了这个,并试图找出它是如何可能的。 NullReferenceException不是每天都会在.net基类中变得很深!SqlDataReader抛出NullReferenceException!什么可能导致这种情况,我该如何调试?

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> 

我唯一能想出是有一个(苗条)的机会有两个线程在同一时间执行相同的方法,并且一个清除或修改被传递到填充DataSet() 。所以我的问题是真的:

  • 这怎么可能例外抛出
  • 莫非多线程的情况下导致此异常
  • 我怎么能肯定,例如,是否有办法,我也可以通过系统步骤.Data方法来复制问题?

顺便说一句,我发现一对夫妇的这一问题的其他情况下,一个在this线程,另一个在某人的页面this谷歌缓存。这两者似乎都没有任何帮助。

正在执行矿的GetTable()方法是这样的:

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(原文如此)是声明为填充有一个SqlDataAdapter一个IDbDataAdapter一个实例变量。数据集是DataSet类型的实例变量。

我的理论是,线程A贯穿并进入SqlDataAdapter.Fill()方法。同时线程B也执行,并做一些事情弄糟线程A,像这一行:

dataAdaptor.SelectCommand.Connection.Close(); 

我可以看到我的这个代码是不是线程安全的,但我怎么能肯定这是问题导致上述例外?

非常感谢您的任何建议!

罗里

编辑:糟糕拼写固定情况。没有在代码中更新它,因为它就是这样。

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

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

+0

“稍有牵强”是这样的代码多线程? 使数据集局部变量,看看它是否再次发生。 – dotjoe 2008-12-15 02:45:36

回答

1

能多线程场景导致此异常ADO.NET类(例如SqlCommand的)的

实例方法通常不是线程安全。 因此,如果您使用来自多个线程的此类实例,则可能会出现问题,例如您描述的问题。

0

我猜测配置数据集会使其所包含的表无效!

BTW你不需要的数据集,您可以直接填写一个数据表 - 或致电它创建了一个数据表为您的其他数据适配器功能(搞定了,我想)

,它的拼写为“适配器”不“adapter”;-)

+0

该死的传统编纂者谁不能拼写!让我感到困惑... 因此,有关如何确保此多线程访问然后处置的任何想法实际上是发生了什么,例如复制该场景? – Rory 2008-12-15 01:06:39

1

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

2

你的数据集不应该是一个类级别的变量。它可能在这两个调用之间或在填充操作期间由另一个线程处置或访问。

prepareDataAdaptor(SPString,CommandType.Text);

dataAdaptor.Fill(dataSet);

相关问题