【VB.Net】SQL文を直接書くときに少し便利になる方法

ソース内にSQL文(特にINSERT)を書くとき、どのようにしていますか?

今回「なるほど」と思った書き方があったので紹介します。

Generic.Dictionary型を使用

ソースの内容

Dim dic As New Dictionary(Of String, Object)
With dic
    .Add("フィールドA", 登録する値1)
    .Add("フィールドB", 登録する値2)
    ...
End With
' SQL文呼び出し
InsertSQL(dic.Keys.ToList)
 
For Each kv As KeyValuePair(Of String, Object) In dic
    ' kv.Key : フィールド名
    ' kv.Value : 登録する値 が入っているので
    ' それらを使用してSqlCommand.ParametersにAddする
Next

' SQL文を実行

それで、InsertSQL関数は以下

Function InsertSQL(fields As List(Of String)) As String
    Dim sbFields As New StringBuilder
    Dim sbValues As New StringBuilder
    For Each s As String In fields
        If sbFields.Length > 0 Then
            sbFields.Append(",")
            sbValues.Append(",")
        End If
        sbFields.AppendLine(s)
        sbValues.AppendLine("?")
    Next
 
    Dim sb As New StringBuilder
    With sb
        .AppendLine("INSERT INTO テーブル名")
        .AppendLine("(")
        .Append(sbFields.ToString)
        .AppendLine(") VALUES (")
        .Append(sbValues.ToString)
        .AppendLine(")")
    End With

    Return sb.ToString
End Function

ポイントはDictionary型を使って
フィールド名とセットする値の連想配列を作っているところです。

この方法でのメリット

急なテーブル設計の変更にも対処可能

特に「列を途中に挿入したい」といった場合、
INSERT文にフィールドを追加して、VALUESの同じ場所に記述して……という
手間が発生します。
列数が多いとさらに大変だと思います。

この方法だと、Dictionaryにフィールド名と値の組み合わせを追加するだけで
(しかも項目の順番を気にすることなく)対応することができます。

共通で使用するクラスに分離が可能

テーブル名を引数に加えることで、関数側は何を意識する必要もなく汎用的に。
呼び出し側は登録するテーブルとフィールドを指定するだけで、SQL文を書く必要がなくなります。

この方法のデメリット

SELECTの結果をINSERTできない
INSERT INTO テーブル名 SELECTFROM ○○

この方法で登録することができません。

Dictionary型の変数に値をセットするときに別途SELECT文を
作成する必要があります。


さいごに

言語はVB.Netですが、考え方自体は他の言語でも通用すると思います。