1

この質問は、SqlDataReader を介したこの単純な反復の理由を見つけるのに役立った以前の 1 つの回答に多少関連しています。

m_aFullIDList = New Generic.List(Of Integer)

While i_oDataReader.Read
    m_aFullIDList.Add(i_oDataReader.GetInt32(0))
End While

m_iTotalNumberOfRecords = m_aFullIDList.Count

すべてのレコードを返すわけではありません。Generic.List がより多くの要素を収容するためにその容量を変更すると (たとえば、2^19 から次の 2^20 に)、この時点で SqlDataReader が簡単に終了し、その Read メソッドはレコードがもうないかのように False を返します。

ほとんどの場合、静かに終了し、例外はまったくスローされません。しかし、時々私は得るでしょう:

NullReferenceException {"オブジェクト参照がオブジェクトのインスタンスに設定されていません。"}

System.Data.SqlClient.SqlDataReader.ReadColumnHeader(Int32 i)
で System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout) で System.Data.SqlClient.SqlDataReader.GetInt32(Int32 i)

リーダーが使用するストアド プロシージャによって返されるすべてのレコード (単一の列) が整数値であることは事実です。行を削除m_aFullIDList.Addし、代わりに値を整数変数に単純に読み取る場合、または汎用リストの容量を既知の多数に事前に割り当てた場合、この問題は発生しません。List が容量を再割り当てする場合にのみ発生するようです - これはリーダーに影響します。

また、この構造体の容量が特定のポイントを超えて再割り当てされるとすぐに、他の構造体 (ArrayList、さらには Array.Resize を使用する Array) を使用しようとしました - これは SqlDataReader を壊します。

この ASP.NET プロジェクトはちょっと複雑なので、reader の実行と List への読み込みだけで構成されるスタンドアロンの単純なプロジェクトで問題を再現しようとすると、問題は発生しません。何が起こっているのか、これをどのように修正できるのか考えていますか?

4

1 に答える 1

0

やっと分かった気がします。

私のコードのロジックには 2 つのステップがありました。SqlDataReader を返す関数を呼び出し、別の関数でそのリーダーを使用してリストを埋めます。

Dim oReader as SqlDataReader = GetTheReader()

FillTheList(oReader)

関数 GetTheReader() は次のようになります。

Function GetTheReader() as SqlDataReader
   Dim oConn As New SqlConnection("Connection String") : oConn.Open()
   Dim oComm As New SqlCommand("Stored Procedure", oConn)

   Dim oReader As SqlDataReader = oComm.ExecuteReader(CommandBehavior.CloseConnection)

   Return oReader
End Function

関数が呼び出し元に戻ったときにスコープ外になったローカル変数として接続を開きました。また、Generic List にデータが取り込まれているとき、別のキャパシティ割り当ての後、ガベージ コレクションが古い変数を破棄して (そしてその接続を閉じて) そのメモリを要求しました。有効な接続のない SqlDataReader が残っていました。

私の現在の解決策は、関数の外部に接続を作成しGetTheReader、それをパラメーターの 1 つとして渡すことです。

于 2013-08-29T20:42:37.887 に答える