DataSetって便利なんですが、裏っかわの仕様をよく理解してないと痛い目にあいます。
今回は型でやられました。
VisualStudio のサーバーエクスプローラからDBの Account というテーブルをDataSetのデザイナにドラッグして下記のようなDataSetを作ります。
このとき、親切すぎる VisualStudio のデザイナはDataTableのみならず、DataRow まで勝手に作ってくれます。
で、この勝手に作ってくれた DataRow(上記のテーブルだと AccountRow)を使うと各カラムへのアクセスがプロパティとして用意されているんですよね。
これを使うと簡単に DataTable 内の目的のデータにアクセスできます。
たとえば DataRow("列名") と書いてたのが DataRow.列名 という感じになります。
それで、今回は下記のようなコードを書いていました。
Dim m_adpAccount As New RhythmSalesProDataSetTableAdapters.AccountTableAdapter()
Dim m_tblAccount As RhythmSalesProDataSet.AccountDataTable = m_adpAccount.GetData()
If m_tblAccount.Count < 1 Then
MessageBox.Show("データなし")
Else
Dim row As TestDataSet.AccountRow = m_tblAccount.Rows(0)
Dim name As String
If row.UserName Is DBNull.Value Then
name = String.Empty
Else
name = row.UserName
End If
End If
データベースから取得してローカル変数に代入する簡単なものですが、DBの値が null のとき If row.UserName Is DBNull.Value Then のところで DBNull ていう例外になるんですよね。
よく考えたらこの TestDataSet.AccountRow.UserName というプロパティ文字列型になっています。ということは中身が DBNull の時点で取得しようとするとプロパティのゲッターの中で例外になるわけですわ。
このプロパティは VisualStudio が勝手に吐いたものなので、DataSet の Designer ファイルをのぞいてみました。
System.Diagnostics.DebuggerNonUserCodeAttribute()> _ Public Property UserName() As String
Get
Try
Return CType(Me(Me.tableAccount.UserNameColumn),String)
Catch e As Global.System.InvalidCastException
Throw New Global.System.Data.StrongTypingException("テーブル 'Account' にある列 'UserName' の値は DBNull です。", e)
End Try
End Get
Set
Me(Me.tableAccount.UserNameColumn) = value
End Set
End Property
やはり文字列にキャストできないときは例外をスローするようになっています。
ということは結局 DataRow("列名") で DBNull かどうか判断せんといかんのかと思いましたが、VisualStuido が勝手に吐くコードの中にこんなメソッドがありました。
Public Function IsUserNameNull() As Boolean
Return Me.IsNull(Me.tableAccount.UserNameColumn)
End Function
どうやらこのメソッドを使えば DBNull を意識しなくてもいいようです。
最終的に下記のように IsUserNameNull() を使って判定するよう修正しました。
Dim row As TestDataSet.AccountRow = m_tblAccount.Rows(0)Dim name As String
If row.IsUserNameNull() Then
name = String.Empty
Else
name = row.UserName
End If
教訓としては、VisualStudio が吐いたコードで DBNull チェックするときは DataRow.列名のプロパティ ではなく、DataRow.Is列名Null() メソッドを使わないといけないということですね。(もしくは DataRow("列名") Is DBNull.Value で判定する方法あり)