SQL文のログ出力

タグの編集
投稿者 YUU  (社会人) 投稿日時 2016/1/3 21:03:18
いつもお世話になっております。

DBネタを連投させていただきます。

現在EFを使わず生のSQL文を実行しております。勉強不足ゆえなのですがSQLを直接記載すると発生するのが文法ミスです。

これでよく実行時にエラーが出力され困っております。そこで、SQL自体をログに出力しようと考えたのですがパラメータの付与されたSQLをうまく出力できません。

何かよき方法はございますでしょうか。お力お貸しいただけると幸いです。
投稿者 るきお  (社会人) 投稿日時 2016/1/4 11:25:47
>そこで、SQL自体をログに出力しようと考えたのですがパラメータの付与されたSQLをうまく出力できません。

これの意味は、次のようなパラメーターが組み込まれた形のSQL文のログ出力には成功してるということでしょうか?
INSERT tablename VALUES(@id)

※パラメーターの表現は対象のDBによって異なる場合があります。@ は SQL Serverの場合です。

実際にじっさいにデータベースが受け取るのは@idのような状態のSQL文なので、
これで、さらにパラメーターの内容まで出力したいということでしたら、自分でループ等を使ってパラメーターの値を逐一ログに出力するしかないと思います。

このようなイメージです。
Imports System.Data.SqlClient

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click


        Dim command As New SqlCommand

        command.CommandText = "INSERT tablename VALUES (@id)"

        Dim pId As New SqlParameter("@id", SqlDbType.Int)
        pId.Value = 627

        command.Parameters.Add(pId)

        Dim log As New Log

        Using cn As New SqlConnection("Server=xxx;Integrated Security=True;")
            log.Write(command.CommandText)
            For Each param As SqlParameter In command.Parameters
                log.Write(param.ParameterName & "=" & param.Value.ToString)
            Next

            cn.Open()
            command.ExecuteNonQuery()
            cn.Close()
        End Using

    End Sub
End Class

Public Class Log

    Public Property LogPath As String = "C:\test\sql.log"

    Public Sub Write(text As String)
        My.Computer.FileSystem.WriteAllText(LogPath, text & vbNewLine, True)
    End Sub
End Class
投稿者 YUU  (社会人) 投稿日時 2016/1/4 21:51:46
返信ありがとうございます。

現行のコードがるきお様に提示していただいた処理と同じような手法を利用しております。
(テキストから張り付けるとインデントがずれる・・・。見難くて申し訳ございません。)
            SQL.AppendLine("SELECT TESTTABLE.[番号],")
            SQL.AppendLine("            TESTTABLE.[名前],")
            SQL.AppendLine("            TESTTABLE.[登録日],")
            SQL.AppendLine("  FROM TESTTABLE")
            SQL.AppendLine(" WHERE TESTTABLE.[番号]    = ?")
            SQL.AppendLine("   AND TESTTABLE.[登録日]  = ?")

            Using cmd As OleDbCommand = db.GetCommand(SQL.ToString)

                aaa.ParamAdd(cmd, "A", OleDbType.VarChar, test.text)
                aaa.ParamAdd(cmd, "B", OleDbType.VarChar, test2.text)

              Debug.Print(SQL.ToString)'ここでパラメータ付与されたSQL文を取得したい。
            End Using

上記のSQL.Tostringにパラメータ部分を追加した状態でログ出力したいのですが。
ログのためにForEachで回すのもどうなのかと考察中です。
クラスないし、メソッドを作って処理から切り離せばまだみやすいのか?。

投稿者 るきお  (社会人) 投稿日時 2016/1/4 22:34:43
>クラスないし、メソッドを作って処理から切り離せばまだみやすいのか?。
そうですね。

私の場合、SQLを実行する部分を切り離してライブラリ化しており、ログ出力もその中でやっています。
ただ、この手の処理はこりすぎるとかえってわかりにくくなるので、ログ出力用のメソッドにOleDbCommandを引数で渡せば、後はうまくログ出力してくれるという作りも良いかもしれません。

なお、データベース側でSQLやパラメーターを補足できる場合もあり、デバッグ用途ならばこちらの方が役に立つ場合もあります。

>(テキストから張り付けるとインデントがずれる・・・。見難くて申し訳ございません。)
この掲示板では CODE か PRE で囲むときれいに出せますよ。

掲示板の説明
http://rucio.cloudapp.net/Usage.aspx
投稿者 daive  (社会人) 投稿日時 2016/1/6 00:08:03
例えば、
プロバイダファクトリクラスを実装して、
クエリをログに残すという事は、VS2005時代から可能でした。
(但し、Oracleサポートは現在はありません。Oracle用Clientを使います。)
これにより、
MS-SQL / OLE-DB / ODBC 接続とクエリを一元管理可能です。
私は、Windows Form / ASP.NET 用に、VB.NET / C# 版で実装して
使っています。
⇒プロバイダファクトリクラスが無い時代に、
  初期の原型版を、VB6&EXCEL-VBA&UDL-FILE&ADO&ODBC/OLEDB/MS-SQLで作りました。
上手に実装してあげると、画面Control と DB 相互のコード量がかなり減ります。
例えば、Control と、要件を渡してあげると、勝手にControlへDBのデータの出し入れが
が出来るような実装も可能です。
(但し、同一クエリで全てを網羅して、MS-SQL/OLE-DB/ODBCを使えるという事ではありません。
 OLE-DB/ODBCは、ワイルドカードや、接続先の方言も考慮する必要があります。)

サイト例
Visual Basic 2010/2008 やさしいADO.NET DBプログラム
http://adonetvb.com/
やさしいDBサンプル
http://adonetvb.com/AdoNetMenu.html
上記他の関連サイト
VB.NET Provider factory class
投稿者 YUU  (社会人) 投稿日時 2016/1/7 15:05:49
返信ありがとうございます。

方向性としましては拡張メソッドで対応という形の予定です。

>この掲示板では CODE か PRE で囲むときれいに出せますよ。

まさかこのような手法があるとは。説明も読まず利用し失礼しました。

>プロバイダファクトリクラス
そうですね。最近上記のクラスの存在を知り作成中ではあるのですが滞っている状況です。

ODBC、Oledbはもちろんのこと複数のプロバイダー、ローカルDB等、多種多様利用するのでうまく作れるとよいのですが。

今回はこれにて解決とさせていただきます。ありがとうございました。