トップ回答者
チェックボックスの値が、サーバーに移動反映しません。関連コードを表示します。

質問
-
Public Sub db_dataset(ByVal n As Integer) ’表示用
Dim ns As Integer
'SQL認証接続
Dim St As String
Dim Cn As New System.Data.SqlClient.SqlConnection
Dim SQL As System.Data.SqlClient.SqlCommand
Dim ServerName As String = "*****" 'サーバー名(またはIPアドレス)
Dim UserID As String = "*****" 'ユーザーID
Dim Password As String = "*****" 'パスワード
Dim DatabaseName As String = "******" 'データソース?
St = "Server=" & ServerName & ";"
St &= "User ID=" & UserID & ";"
St &= "Password=" & Password & ";"
St &= "Initial Catalog=" & DatabaseName
Cn.ConnectionString = St
SQL = Cn.CreateCommand
Cn.Open()Dim ds = New DataSet
Dim sq As String
sq = "SELECT * FROM dbo.[サーバー内のテーブル名]"
Dim adapter = New SqlClient.SqlDataAdapter()
adapter.SelectCommand = New SqlClient.SqlCommand(sq, Cn)
adapter.SelectCommand.CommandType = CommandType.Text
adapter.Fill(ds)Dim dt As New DataTable
dt = ds.Tables(0)
Me.DataGridView1.DataSource = dt
ns = ds.Tables(0).Rows.Count
Me.TX_Client_ID.Text = dt.Rows(n).Item("Client_ID").ToString
Me.CB_CustomerType.Text = dt.Rows(n).Item("CustomerType").ToString
Me.CK_FLG_Branch.Text = dt.Rows(n).Item("FLG_Branch").ToString ←ここです!
Cn.Close()
End Sub
'修正(変更)
Private Sub TB_F3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TB_F3.Click
'SQL認証接続
ここに、前記と同じものがきます(長くなるので省略します)。
Cn.Open()'修正・変更SQL
Dim M_Client_ID As Integer
M_Client_ID = NZ(Me.TX_Client_ID.Text)----NZは自作関数(Null値対策用)です。
M_Client_ID = CInt(M_Client_ID)Dim M_CustomerType As Integer
M_CustomerType = NZ(Me.CB_CustomerType.Text)
M_CustomerType = CInt(M_CustomerType)
'YES/No チェックボックス
Dim M_FLG_Branch As Boolean
M_FLG_Branch = NZbool(Me.CK_FLG_Branch.Text) 'Yes/NO ← ここです! NZboolは自作関数です。Dim SQLst As String
SQLst = "UPDATE dbo.[サーバー内のテーブル名] SET "
SQLst &= "CustomerType= " & M_CustomerType & ", "
'Yes/No チェックボックス 未解決
SQLst &= "FLG_Branch= " & M_FLG_Branch & " " '**データ型不明 YES/NO チェックボックス ← ここです!
SQLst &= "WHERE Client_ID = " & M_Client_ID & " "
SQL.CommandText = SQLst
SQL.ExecuteNonQuery()MessageBox.Show(" ' 変更しました。 チェックボックスが、まだ変更ができない状態です(PG不備)。 研究中です! ")
Call db_dataset(dn)
Me.TX1.Text = dnCn.Close()
End Sub
以下、NZ,NZbool です。
Module Module1Public Function NZ(ByVal a)
If a = "" Then
a = 0
ElseIf IsDBNull(a) = True Then
a = 0
ElseIf IsNothing(a) = True Then
a = 0
End IfNZ = a
End FunctionPublic Function NZbool(ByVal a As String) As Boolean
If a = "False" Then
a = False
ElseIf a = "True" Then
a = True
End IfNZbool = a
End Function
End Module
回答
-
あと文字列を結合してクエリを生成してますが、SQLインジェクション攻撃を受ける可能性があります。
初心の方には難しいかも知れませんが、今のうちからしっかり勉強しておくことをお勧めします。以下関連スレッドです。
http://social.msdn.microsoft.com/Forums/ja/vbgeneralja/thread/3bf2f63d-da18-4003-bd8e-656fe5698dc6
参考までにパラメタライズドクエリを使ってコードを書き直してみました。動作は保証しませんが、何かの参考になれば幸いです。
'修正(変更) Private Sub TB_F3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TB_F3.Click 'SQL認証接続 Dim ServerName As String = "*****" 'サーバー名(またはIPアドレス) Dim UserID As String = "*****" 'ユーザーID Dim Password As String = "*****" 'パスワード Dim DatabaseName As String = "******" 'データソース? Dim St = "Server=" & ServerName & ";" St &= "User ID=" & UserID & ";" St &= "Password=" & Password & ";" St &= "Initial Catalog=" & DatabaseName Using con As New System.Data.SqlClient.SqlConnection(St) con.Open() '修正・変更SQL Dim SQLst As String SQLst = "UPDATE dbo.[サーバー内のテーブル名] SET " SQLst &= "CustomerType= @CustomerType, " SQLst &= "FLG_Branch= @FLG_Branch " SQLst &= "WHERE Client_ID = @Client_ID " Dim sql As New System.Data.SqlClient.SqlCommand(SQLst, con) sql.Parameters.AddWithValue("@CustomerType", NZInt32(Me.CB_CustomerType.Text)) sql.Parameters.AddWithValue("@FLG_Branch", NZBool(Me.CK_FLG_Branch.Text)) sql.Parameters.AddWithValue("@Client_ID", NZInt32(Me.TX_Client_ID.Text)) sql.ExecuteNonQuery() MessageBox.Show("変更しました。") Me.db_dataset(dn) Me.TX1.Text = dn End Using End Sub Module Module1 Public Function NZInt32(value As String) As Int32 Dim ret = 0 Int32.TryParse(value, ret) Return ret End Function Public Function NZBool(value As String) As Boolean Dim ret = False Boolean.TryParse(value, ret) Return ret End Function End Module
ひらぽん http://d.hatena.ne.jp/hilapon/
- 編集済み ひらぽんModerator 2012年4月13日 6:15
- 回答としてマーク yksaila 2012年4月13日 10:18
すべての返信
-
>SQLst &= "FLG_Branch= " & M_FLG_Branch & " " '**データ型不明 YES/NO チェックボックス ← ここです!
上記の式の結果は、
FLG_Branch=False
になります。この場合、SQL ServerはFLG_Branchという列に、Falseという列の値をセットしようとします。
そうではなく、Falseという値を入れたいのであれば、以下のようにする必要があります。FLG_Branch='False'
上記のようになるようにコードを修正して下さい。これでうまくいくようになりますが、実際にはSQL ServerがFalseという文字列からBit型に自動的に変換して保存してくれます。
また、NZやNZboolという関数を作成されていますが、SQL Serverにはisnullという関数が用意されていますので、これを使えばnullの場合に返す値を指定できます。
(追記)ご質問の内容的にはSQL Serverのスレッドというより、VBのスレッドの方が適切だと思います。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
- 編集済み trapemiyaModerator 2012年4月13日 4:18 追記
-
NZBool の実装は、以下のような感じでいいと思います。
Public Function NZbool(value As String) As Boolean Dim ret = False Boolean.TryParse(value, ret) Return ret End Function
ひらぽん http://d.hatena.ne.jp/hilapon/
- 編集済み ひらぽんModerator 2012年4月13日 4:46
-
あと文字列を結合してクエリを生成してますが、SQLインジェクション攻撃を受ける可能性があります。
初心の方には難しいかも知れませんが、今のうちからしっかり勉強しておくことをお勧めします。以下関連スレッドです。
http://social.msdn.microsoft.com/Forums/ja/vbgeneralja/thread/3bf2f63d-da18-4003-bd8e-656fe5698dc6
ひらぽん http://d.hatena.ne.jp/hilapon/
-
あと文字列を結合してクエリを生成してますが、SQLインジェクション攻撃を受ける可能性があります。
初心の方には難しいかも知れませんが、今のうちからしっかり勉強しておくことをお勧めします。以下関連スレッドです。
http://social.msdn.microsoft.com/Forums/ja/vbgeneralja/thread/3bf2f63d-da18-4003-bd8e-656fe5698dc6
参考までにパラメタライズドクエリを使ってコードを書き直してみました。動作は保証しませんが、何かの参考になれば幸いです。
'修正(変更) Private Sub TB_F3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TB_F3.Click 'SQL認証接続 Dim ServerName As String = "*****" 'サーバー名(またはIPアドレス) Dim UserID As String = "*****" 'ユーザーID Dim Password As String = "*****" 'パスワード Dim DatabaseName As String = "******" 'データソース? Dim St = "Server=" & ServerName & ";" St &= "User ID=" & UserID & ";" St &= "Password=" & Password & ";" St &= "Initial Catalog=" & DatabaseName Using con As New System.Data.SqlClient.SqlConnection(St) con.Open() '修正・変更SQL Dim SQLst As String SQLst = "UPDATE dbo.[サーバー内のテーブル名] SET " SQLst &= "CustomerType= @CustomerType, " SQLst &= "FLG_Branch= @FLG_Branch " SQLst &= "WHERE Client_ID = @Client_ID " Dim sql As New System.Data.SqlClient.SqlCommand(SQLst, con) sql.Parameters.AddWithValue("@CustomerType", NZInt32(Me.CB_CustomerType.Text)) sql.Parameters.AddWithValue("@FLG_Branch", NZBool(Me.CK_FLG_Branch.Text)) sql.Parameters.AddWithValue("@Client_ID", NZInt32(Me.TX_Client_ID.Text)) sql.ExecuteNonQuery() MessageBox.Show("変更しました。") Me.db_dataset(dn) Me.TX1.Text = dn End Using End Sub Module Module1 Public Function NZInt32(value As String) As Int32 Dim ret = 0 Int32.TryParse(value, ret) Return ret End Function Public Function NZBool(value As String) As Boolean Dim ret = False Boolean.TryParse(value, ret) Return ret End Function End Module
ひらぽん http://d.hatena.ne.jp/hilapon/
- 編集済み ひらぽんModerator 2012年4月13日 6:15
- 回答としてマーク yksaila 2012年4月13日 10:18
-
以下のようにして、解決しました。
回答していただいた方全員にお送りしたいのですが、うるさくなると困りますのでここに記載します。
皆様、ありがとうございました。 まだ、フォーラムの使い方になれていませんので(今日で4日目?)、ご迷惑をおかけしました。
お許しください。
以下、解決内容です(一部残っていますが、基本的には解決です)。
1.VBのチェックボックス自体が、チェックを変更しても変わらなかったので、下記のコードを追加しました。
もともと、そうなのか、私の設定が違っていたのかは、不明です。Private Sub CK_FLG_Branch_Click(sender As System.Object, e As System.EventArgs) Handles CK_FLG_Branch.Click
If Me.CK_FLG_Branch.Text = False Then
Me.CK_FLG_Branch.Text = True
ElseIf Me.CK_FLG_Branch.Text = True Then
Me.CK_FLG_Branch.Text = False
End If
End Sub2.チェックボックスのプロパティの「CheckState」を、’Checked’にしておきます。
3.プログラムコード内の定義を以下のようにします。
'YES/No チェックボックス
Dim M_FLG_Branch As String ’← ’***
M_FLG_Branch = Me.CK_FLG_Branch.Text 'Yes/NO
M_FLG_Branch = NZbool(M_FLG_Branch) ’自作関数:NZbool’***
理由:クライアントには、Booleanでなく、Stringとして渡しているようなので、上記のように定義しました。
4.’Nzbool’は、自作関数です。Public Function NZbool(ByVal a)
If a = "False" Then
a = 0
ElseIf a = "True" Then
a = -1
End IfNZbool = a
End Function5.SQLサーバー側では、Yes/No(Boolean)を、-1/0として扱っているので、こうしました。
6.チェックボックスの☑が、True/Falseの表示に対応していません。(2)が、おかしいのかも?
たぶん、チェックボックスの設定がいけないのでしょう。
もう少し、ここはやってみます。 わからなければ、また質問します。今回は、おかげさまでサーバーへの書き込みは成功しました。
ありがとうございました。
これで、うまくいきました。 -
ひらぽんさんへ、
ご教示ありがとうございました。 SQLインジェクションについても勉強しました。 まだ完全には自分のものには、なっていませんが、時間をかけて勉強します。
コードも大変参考になりました。パラメタライズドクエリをこれから心がけます。
さて、二点質問させてください。
1.SQLインジェクションの件ですが、サーバーに侵入されず、クライアント側からでも攻撃できるのでしょうか(クライアントには、.EXEしか置きません)?
クライアント側からサーバーへの侵入を相当に防御している場合も(ま、これも程度問題ですが)、危険性がありますか?
2.先に教えていただいたコードの中: Using con As New System.Data.SqlClient.SqlConnection(St) ~ End Usingのあいだに、con.Open()があってCon.Close()がないのですが、
かまわないのでしょうか? それとも、End Usingがあるので良いのでしょうか?
以上です、よろしくお願いします。
勉強を始めたばかりで的外れの発言もあるでしょうが、この点はお許しください。
yksaila
-
まず SQL インジェクションですが、クライアント側から入力値にクエリ文字列を設定して攻撃を行う手法です。パラメタライズドクエリを用いず、文字列の結合でクエリを生成している場合セキュリティホールとなるため、SQL インジェクション攻撃を受ける恐れが高くなりますが、SqlCommand.Parameters でパラメータを設定すると、仮にクエリを設定しても文字列として扱われるため、SQL インジェクション攻撃の回避ができます。
http://itpro.nikkeibp.co.jp/article/MAG/20070608/274192/
http://www.atmarkit.co.jp/fdotnet/basics/adonet03/adonet03_02.html
次に SqlConnection の Closeですが、Using ステートメントを抜ける際、Close メソッドとDispose メソッドが呼ばれ、接続を閉じるのとオブジェクトを解放することが保証されてます。http://msdn.microsoft.com/ja-jp/library/system.data.sqlclient.sqlconnection(v=vs.80).aspx
Using ステートメントの解説も読んでみてください。
http://msdn.microsoft.com/ja-jp/library/htd05whh.aspx
ひらぽん http://d.hatena.ne.jp/hilapon/