S2Dao.NETでバイナリをログ出力できるようにしてみた
うちの会社、最近Seasar2(S2Container.NET)をフレームワークに使って開発することがだいぶ増えてきています。
ご多分に漏れず僕が今やってるプロジェクトもそうです。
そのシステムでS2Dao.NET(以下.NETを省略しますが.NET版の話です)が出力するSQLログをとっておいて
障害復旧に使うという仕組みを入れています。
ただこのシステム、バイナリ(jpgとxls)をInsertする場面があります。
バイナリのデータはEntity上ではByte配列で保持しています。
その部分がSQLログの上では'System.Byte'と表示されてしまいます。
バイナリをどうやって障害復旧するか考えていました。
使っているDBMSはAccessで、調べてみたところAccessは0x....の16進数方式で
SQL文を書いてやればバイナリのInsertができるようです。
そこで、SQLログに16進を出力してやろうと考え
S2Daoのソースを見て改良を加えてみました。
S2Daoのソースを読んでみた分かったのは
・S2DaoはDBMSに送ったSQLを忠実に出力しているわけではない
・↑ADO.NETのParameters.Addで変数をバインドしてSQLをDBMSに発行しているためSQLが取得できない?
・ログに出力するSQLはSeasar.Extension.ADO.Impl.BasicCommandFactoryのGetCompleteSqlメソッドで生成している
・さらにその中で、?で表されている変数をバインドするためにReplaceSqlメソッドを呼んでいる
・さらにさらに、バインドする変数をGetBindVariableTextにかけてログ用のテキストにしている
さてその、GetBindVariableTextの中身を見ると
>>
>|cs|
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となりますからね。
そんなわけで
>>
>|cs|
else if (bindVariable is byte)
{
return "0x" + BitConverter.ToString((byte)bindVariable).Replace("-", string.Empty);
}
||<
<<
を加えて、SQLログに0x...形式の16進バイナリ文字列がでるようにしましたとさ。
ちなみに、VisualStudioのデバッグウィンドへの出力って結構時間がかかるので
大きなバイナリをInsertするとログ表示に結構時間がかかります。