S2Dao.NETでバイナリをログ出力できるようにしてみた

うちの会社、最近Seasar2S2Container.NET)をフレームワークに使って開発することがだいぶ増えてきています。
ご多分に漏れず僕が今やってるプロジェクトもそうです。


そのシステムでS2Dao.NET(以下.NETを省略しますが.NET版の話です)が出力するSQLログをとっておいて
障害復旧に使うという仕組みを入れています。
ただこのシステム、バイナリ(jpgとxls)をInsertする場面があります。
バイナリのデータはEntity上ではByte配列で保持しています。
その部分がSQLログの上では'System.Byte[]'と表示されてしまいます。
バイナリをどうやって障害復旧するか考えていました。
使っているDBMSAccessで、調べてみたところAccessは0x....の16進数方式で
SQL文を書いてやればバイナリのInsertができるようです。
そこで、SQLログに16進を出力してやろうと考え
S2Daoのソースを見て改良を加えてみました。


S2Daoのソースを読んでみた分かったのは
S2DaoDBMSに送ったSQLを忠実に出力しているわけではない
・↑ADO.NETのParameters.Addで変数をバインドしてSQLDBMSに発行しているためSQLが取得できない?
・ログに出力するSQLSeasar.Extension.ADO.Impl.BasicCommandFactoryのGetCompleteSqlメソッドで生成している
・さらにその中で、?で表されている変数をバインドするためにReplaceSqlメソッドを呼んでいる
・さらにさらに、バインドする変数をGetBindVariableTextにかけてログ用のテキストにしている


さてその、GetBindVariableTextの中身を見ると

if (bindVariable is INullable)
            {
                INullable nullable = bindVariable as INullable;
                if (nullable.IsNull)
                {
                    return GetBindVariableText(null);
                }
                else
                {
                    PropertyInfo pi = bindVariable.GetType().GetProperty("Value");
                    return GetBindVariableText(pi.GetValue(bindVariable, null));
                }
            }
#if NHIBERNATE_NULLABLES
            else if (bindVariable is INullableType)
            {
                INullableType nullable = bindVariable as INullableType;
                if (!nullable.HasValue)
                {
                    return GetBindVariableText(null);
                }
                else
                {
                    PropertyInfo pi = bindVariable.GetType().GetProperty("Value");
                    return GetBindVariableText(pi.GetValue(bindVariable, null));
                }
            }
#endif
            else if (bindVariable is string)
            {
                return "'" + bindVariable + "'";
            }
            else if (bindVariable == null)
            {
                return "null";
            }
〜中略〜
            else
            {
                return "'" + bindVariable + "'";
            }

という風になっています。
つまりバイナリを格納しているByteはどこのifにも引っかからずに最後のelseで'System.Byte'として出力されていたわけです。
#Byte[]をToStringしたら内容はでずにSystem.Byteとなりますからね。
そんなわけで

            else if (bindVariable is byte[])
            {
                return "0x" + BitConverter.ToString((byte[])bindVariable).Replace("-", string.Empty);
            }

を加えて、SQLログに0x...形式の16進バイナリ文字列がでるようにしましたとさ。
ちなみに、VisualStudioのデバッグウィンドへの出力って結構時間がかかるので
大きなバイナリをInsertするとログ表示に結構時間がかかります。