DataGridView1のセル入力有無の判定について

タグの編集
投稿者 fredee  (社会人) 投稿日時 2009/2/16 19:39:54
お世話にまります。
VB2008EXP SP1でデータグリッドビューを使ってデータベースのテーブルを更新するプログラムを作っています。データベースはSqlServer2005Expを使っています。
データグリッドビューのセルが入力されたら全角半角チェックをし、何も入力しない場合はチェックしないようにしています。その例を下記に記します。
<例>
If Me.DataGridView1.CurrentCell.Value = Nothing Then Exit Select  '何も入力しない時
この記述を、Windows Vista(Business) で実行すると問題ないのですが
Windows XP SP3の環境で実行すると、「何も入力しない」 = Nothing 条件に引っかからないのは何故でしょうか?
因みに、XP側で
If Me.DataGridView1.CurrentCell.Value = "" Then Exit Select
のように、 Nothing を "" で置き換えても同じでした!(条件に引っかからない)

何方かご教授をお願い致します。

投稿者 るきお  (社会人) 投稿日時 2009/2/16 21:46:14
こんにちは。
VistaとXPとで反応が異なるという話は私は効いたことがないです。

まだ情報が足りないです。
特にVistaとXPでの違いを確認するためにはどのような手順で操作すればよいでしょうか?
再現可能なコードと手順の両方があれば手がかりになります。

たとえば、以下のコードでも再現しますか?
Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
      
        Dim table As New Data.DataTable

        table.Columns.Add("名前"GetType(String))
        table.Columns.Add("英語"GetType(Integer))
        table.Columns.Add("国語"GetType(Integer))
        table.Columns.Add("数学"GetType(Integer))
        table.Columns.Add("備考"GetType(String))

        table.Rows.Add("徳川家康", 90, 85, 65, "aaa")
        table.Rows.Add("豊臣秀吉", 55, 85, 70, "")
        table.Rows.Add("織田信長", 82, 90, 85, "")
        table.Rows.Add("松永久秀", 80, 80, 80, "")

        DataGridView1.DataSource = table

    End Sub

    Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click

        If Me.DataGridView1.CurrentCell.Value = Nothing Then
            MsgBox("Nothingです。")
        Else
            MsgBox("Nothingではないです。")
        End If

    End Sub


このコードを実行すると1行目の5列目をクリックしてから、Button1をクリックすると「Nothingではないです」、2行目の5列目をクリックしてから、Button1をクリックすると「Nothingです」と表示されますか?

それから、 = Nothing という記述は一般的ではありませんし、紛らわしい場合があるので辞めておいた方が良いです。
fredeeさんのコードでは意味的には = "" がふさわしいと思います。
Nothingは意味的には "" と異なっており、 = Nothingと記述した場合の動作はNothingの意味から考えるとやや特殊なのでこのように記述しないことが多いです。
投稿者 刈谷勇  (社会人) 投稿日時 2009/2/16 23:09:11
こんにちは、fredeeさん、るきおさん。

自分の環境はVB2005EEでXPですが、るきおさんのコードでテストしましたが、何も入力されていないセルでは、”Nothingです。”と表示されました。
ただ、DataTableを使っている為新規の行の場合、何も入力されていないセルの値はDBNULLになります。

とりあえず、XPで何も入っていないセルの値がなにになっているかを知れべた方がいいと思います。

あと、別のXPがあればそちらでも確認したほうがいいと思います。
DataGridViewではないですが、マウスドライバーの不具合(?)で期待した値が帰ってこないということを経験したことがあります。
投稿者 fredee  (社会人) 投稿日時 2009/2/17 04:07:47
刈谷勇さん、るきおさん 回答有難う御座います。
色々と調べたところ、DataGridView1ではなくてデータベースのテーブルにレコードを追加する時の処理でが問題のようです!!
下の要領で、タブ区切りのテキストファイルを配列変数へセットし、その変数をテーブルへ出力していますが、この時、ある項目にデータが無い場合のテーブルの値が変です。
<記述>
SrFile = New StreamReader(PC_Fold & "size.txt", Encoding.Default)
Sline = SrFile.ReadLine
While Not Sline Is Nothing
    If Sline.Length <> 0 Then
       ICnt += 1
        Dim StrDATA() As String = Split(Sline, vbTab)   '区切り文字コロン(タブ)
        Try
           StrDATA(0) = Trim(StrDATA(0))               'キー
             StrDATA(2) = Trim(StrDATA(2))
             StrDATA(3) = Trim(StrDATA(3))
           StrDATA(4) = Trim(StrDATA(4))
           StrDATA(5) = Trim(StrDATA(5))
           SqlCmd.CommandText = "SELECT COUNT(*) FROM [size_tbl] WHERE サイズ区分 = '"                    & StrDATA(0) & "'"
           SqlCmd.CommandText = "INSERT INTO [size_tbl] VALUES ('" & StrDATA(0)                    & "', '" _
                  & StrDATA(1) & "', '" _
                              & StrDATA(2) & "', '" _
                              & StrDATA(3) & "', '" _
                              & StrDATA(4) & "', '" _
                              & StrDATA(5) & "')"
           Try
            SqlCmd.ExecuteNonQuery()
            ACnt += 1
           Catch ex As Exception
              ECnt += 1
              MessageBox.Show(ex.Message)
           End Try
       Catch ex As Exception
             MessageBox.Show(ex.Message)
       End Try
このように記述しています。長くなって申し訳ありません!
例えば、StrDATA(3)に何も入っていない場合、StrDATA(3)は=""になっています。
If StrDATA(3) = "" Then
    Debug.Print(StrDATA(3))
End If
で判定しても、Debug.Print(StrDATA(3))のへ移りません。
StrDATA(3)の変数の内容が分かりません。
宜しくお願いします。

投稿者 るきお  (社会人) 投稿日時 2009/2/17 07:27:35
>If StrDATA(3) = "" Then
>    Debug.Print(StrDATA(3))
>End If
>で判定しても、Debug.Print(StrDATA(3))のへ移りません。
それはどのようにして確認しましたか?
イミディエイトウィンドウと出力ウィンドウを確認しましたか?
また、出力されているとしても 空文字が出力されるので肉眼での確認はかなり困難かもしれません。
たとえば、Debug.Print(">" & StrDATA(3) & "<")にすれば、StrDATA(3)が空でも"><"と出力されるので確認しやすいです。

なお、値の確認だけが目的なら単純にDebug.Printの行にブレイクポイントを設置して、
一時停止中にStrDATAを右クリックしてクイックウォッチを選択するという方法もあります。

それから、プログラムの内容がどうも業務系に感じたので一言付け加えます。
SQL文に変数を & でくっつけていくのではなくパラメータを使うのが一般的です。
SqlCmd.Parameters.Addで追加できます。

そうしないとこのCSV経由でSQLインジェクションされる危険があります。
それに多くのデータベースエンジンはパラメータクエリの方が効率よく処理できます。
投稿者 fredee  (社会人) 投稿日時 2009/2/17 17:03:48
るきおさん 親切なアドバイスを頂きまして有難うございます。

>それはどのようにして確認しましたか?
If StrDATA(3) = "" Then ここにブレークポイントを設定し、ステップ実行で行いました。
>一時停止中にStrDATAを右クリックしてクイックウォッチを選択するという方法もあります。
これで確認しました。

タブだけの時、StrDATA(3)の変数に何が入ってくるのかが分かればチェックが出来ると思うのですが!

>SQL文に変数を & でくっつけていくのではなくパラメータを使うのが一般的です。
>SqlCmd.Parameters.Addで追加できます。

>そうしないとこのCSV経由でSQLインジェクションされる危険があります。
>それに多くのデータベースエンジンはパラメータクエリの方が効率よく処理できます。 
データベースを使ってのプログラミングが初級者で、SQL文も勉強不足なもので
もっと勉強します。アドバイス有難う御座います。
投稿者 刈谷勇  (社会人) 投稿日時 2009/2/17 19:28:40
え~と、内容を整理させてください。

質問
SQLのInsertを行うときに登録内容にtabのみのデータがあり、それデータに対して何らかのアクションを行いたい。

でよろしいでしょうか?


であれば、
If (TextBox1.Text = vbTab) Then
    MessageBox.Show("tabです")
End If

で、チェックできますよ。


もし、質問内容が違うようでしたら、一度質問内容をまとめていただいたほうが解決が早いと思います。
投稿者 るきお  (社会人) 投稿日時 2009/2/17 21:19:30
私も話がわからなくなってきました…。

>で判定しても、Debug.Print(StrDATA(3))のへ移りません。
とあるのに
>>一時停止中にStrDATAを右クリックしてクイックウォッチを選択するという方法もあります。
>これで確認しました。
というところで混乱しました。

>タブだけの時、StrDATA(3)の変数に何が入ってくるのかが分かればチェックが出来ると思うのですが!
クイックウォッチで確認したのでは??

タブが連続している場合、Splitで区切るとその間にあるデータは""になります。
投稿者 fredee  (社会人) 投稿日時 2009/2/17 23:21:35
刈谷勇さん、るきおさん 大変有難う御座いました。
どう質問していいのか、結果だけで判断して纏まりのない質問になり申し訳御座いませんでした!
下記のように変更する事で解決いたしました。
基本的な解決かどうか疑問ですが、刈谷勇さん、るきおさん にはお世話になりました。 

テキストファイルを読んで配列変数に格納してテーブルへインサートする方法を止めて、
"SQLDMO.BulkCopy" を使って、.ImportData(BCP)でインポートする方法に変えたら、
タブだけの項目のが、If Me.DataGridView1.CurrentCell.Value = "" Then Exit Select
で判定出来ました。

<インポートの方法>
Dim SVR As Object                         'サーバーオブジェクト用
Dim ODB As Object                        'テーブルオブジェクト用
Dim BCP As Object                         'バルクコピーオブジェクト用
SVR = CreateObject("SQLDMO.SQLServer")
ODB = CreateObject("SQLDMO.Database")
BCP = CreateObject("SQLDMO.BulkCopy")
With SVR                                    
     .EnableBcp = True
    .LoginSecure = True              'SQLServerにWindows認証で接続                   
    .Connect(SerVer, "sa", "")
End With
ODB = SVR.Databases(TestDB)          'データベース接続
BCP = New SQLDMO.BulkCopy
With BCP
      .DataFilePath = PC_Fold & "Test.txt"
       .DataFileType = 2              'タブ区切り
       .SuspendIndexing = True
      .RowDelimiter = vbCrLf         '改行
End With
ODB.Tables("Test_tbl").ImportData(BCP)       'インポート