2016-11-18 11 views
-1

私がReadループに到達すると、インデックスが範囲外になります。私は読者の秩序の価値については思っていますが、なぜ私はそれを得ているのか分かりません。インデックスが境界外の例外を返しているのはなぜですか?

Private Function Create(Reader As SqlDataReader) As IEnumerable(Of MyObject) 

     SetOrdinals(MyObjectReader) 
     Dim MyObjects = New List(Of MyObject) 

     While MyObjectReader.Read() 
      Dim Temp = New MyObject() With { 
       .FirstValue = MyObjectReader.GetValue(Of Integer)(MyObjectReader(FirstValue_Ord)), 
       .SecondValue = If(MyObjectReader.GetValue(Of String)(MyObjectReader(SecondValue_Ord)), String.Empty).Trim(), 
       .ThirdValue = If(MyObjectReader.GetValue(Of String)(MyObjectReader(ThirdValue_Ord)), String.Empty).Trim(),     
      MyObjects.Add(Temp) 
     End While 
     Return MyObjects 

    End Function 

    Private Sub SetOrdinals(MyObjectReader As SqlDataReader) 
     FirstValueOrd = MyObjectReader.GetOrdinal("FirstValue") 
     SecondValue_Ord = MyObjectReader.GetOrdinal("SecondValue") 
     ThirdValue_Ord = MyObjectReader.GetOrdinal("ThirdValue")   
    End Sub 

End Class 


Public Module Extensions 

    <Extension> 
    Function GetValue(Of T)(rdr As SqlDataReader, i As Integer) As T 
     If rdr.IsDBNull(i) Then 
      Return Nothing 
     End If 
     Return DirectCast(rdr.GetValue(i), T) 
    End Function 
End Module 
+0

あなたは車輪を再発明しているようですね! 'SqlDataReader'には' GetString'や 'GetInteger'などのメソッドがあり、' GetValue'メソッドの処理を行います。 –

+0

@ChrisDunawayこの遅れて申し訳ありません。 'GetString'などのメソッドではヌルチェックが必要です。そのため、私は' DataRow'の拡張メソッドと同様に[元の質問](http://stackoverflow.com/a/40683355)の 'GetValue'拡張を提案しました。それを処理するより良い方法はありますか? – Mark

答えて

2

あなただけGetValue呼び出しに序数を渡しする必要があります。

ここ
While MyObjectReader.Read() 
    Dim Temp = New MyObject() With { 
     .FirstValue = MyObjectReader.GetValue(Of Integer)(FirstValue_Ord), 
     .SecondValue = If(MyObjectReader.GetValue(Of String)(SecondValue_Ord), String.Empty).Trim(), 
     .ThirdValue = If(MyObjectReader.GetValue(Of String)(ThirdValue_Ord), String.Empty).Trim() 
    } 
    MyObjects.Add(Temp) 
End While 
+0

申し訳ありませんが、完全にコードをコピーしていませんでした。実際のコードはOrdinalを使用しています – Robert

+0

@Robert違いは、パラメータは単にMyObjectReader(FirstValue_Ord)の代わりに序数 - FirstValue_Ordであることです。 – Mark

0

私のバージョン:)

Private Function Create(reader As SqlDataReader) As IEnumerable(Of MyObject) 
    Dim objects As New List(Of MyObject)()   

    Dim ordinals As New Ordinals(reader) 
    While reader.Read() 
     Dim Temp As New MyObject With 
     { 
      .FirstValue = reader.GetValueOrDefault(Of Integer)(ordinals.FirstValue), 
      .SecondValue = reader.GetValueOrDefault(ordinals.SecondValue, "").Trim(), 
      .ThirdValue = reader.GetValueOrDefault(ordinals.ThirdValue, "").Trim() 
     } 

     objects.Add(Temp) 
    End While 
    Return MyObjects 

End Function 

Private Class Ordinals 
    Public Property FirstValue As Integer 
    Public Property SecondValue As Integer 
    Public Property ThirdValue As Integer 

    Public Sub New(reader As SqlDataReader) 
     FirstValue = reader.GetOrdinal(nameOf(FirstValue)) 
     SecondValue = reader.GetOrdinal(nameOf(SecondValue)) 
     ThirdValue = reader.GetOrdinal(nameOf(ThirdValue)) 
    End Sub 
End Class 


Public Module Extensions 
    <Extension> 
    Function GetValueOrDefault(Of T)(reader As SqlDataReader, ordinal As Integer) As T 
     Return reader.GetValueOrDefault(Of T)(ordinal, Nothing) 
    End Function 

    <Extension> 
    Function GetValueOrDefault(Of T)(reader As SqlDataReader, 
            ordinal As Integer, 
            defaultValue As T) As T 
     Dim value = reader(ordinal) 
     If value = DbNull.Value Then 
      Return defaultValue 
     End If 
     Return DirectCast(value, T) 
    End Function 
End Module 

拡張メソッドは、既に抽出されたオブジェクトに対してDbNull.Valueのチェックを実行しているのでSqlDataReaderから同じ値を2回読み取ることを取り除きます。
SqlDataReader.IsDbNull(index)は、DbNullをチェックする前に値を読み取ります。

拡張メソッドには2つのオーバーロードがあります。
- 値がDbNull.Valueの場合、指定された型のデフォルト値を返すメソッドです。 vb.netのNothingはtypeのデフォルト値です。
- 値がDbNull.Valueの場合、戻りたいデフォルト値のパラメータを取るもの。可能性のあるデフォルト値を渡すと、新しいオブジェクトを作成する行が短くて読みやすくなります。インラインifの声明を取り除きます。

名前がGetValueの拡張メソッドには「副作用」があります。このメソッドの名前消費者は、SqlDataReaderから値を取得することを期待します。したがって、データベースクエリがNULLを返す場合はDbNull.Valueを得ることができますが、文字列の場合はnull、整数の場合は0となります。名前GetValueOrDefaultは少し有益ですので、何をしているのかを調べるためにメソッドの中に入る必要はありません。

関連する問題