DbDataAdapter.DisposeはDbCommandオブジェクトをDisposeしない

大量にDbDataAdapter使うコードで、途中でFillできなくなって調べた結果です。

System.Data.Common.DbDataAdapterにはSystem.Data.IDbDataAdapterインターフェースの実装であるSelect/Insert/Update/DeleteCommandプロパティがあり、これらのプロパティにはSystem.Data.IDbCommand型のオブジェクトの設定/取得が可能です。

そして、DbDataAdapter.Disposeメソッドを呼び出しても、この4つのコマンドオブジェクトはDisposeされず、nullが設定されるだけです。したがって、各プロパティに設定したコマンドオブジェクトは、そのコマンドオブジェクトを生成する側で、明示的にDisposeしてやらないといけません。

[参照]
https://github.com/Microsoft/referencesource/blob/master/System.Data%2FSystem%2FData%2FCommon%2FDbDataAdapter.cs#L236

override protected void Dispose(bool disposing) { // V1.0.3300, MDAC 69629
    if (disposing) { // release mananged objects
        IDbDataAdapter pthis = (IDbDataAdapter) this; // must cast to interface to obtain correct value
        pthis.SelectCommand = null;
        pthis.InsertCommand = null;
        pthis.UpdateCommand = null;
        pthis.DeleteCommand = null;
    }
    // release unmanaged objects
    base.Dispose(disposing); // notify base classes
}

最初、どうしてこうなってるのかなーと思ったのですが、DbDataAdapterはあくまでAdapterであって、Compositionではないからかと納得しました。どういうことかというと、DbDataAdapterへの各コマンドの付け外しは自由自在なので、DbDataAdapterがコマンドオブジェクトの死活管理を行うことはできないんですよね。

ハマりかけてなるほどなぁという話でした。

コメントを残す