バージョン 1.0.82.0に同梱されているデザイナーで生成されたデータセット/テーブルアダプターを使用して同じ問題が発生しましSystem.Data.Sqlite.dll
た。接続を閉じた後、を使用してデータベース ファイルを読み取ることができませんでしたSystem.IO.FileStream
。接続とテーブルアダプターの両方を正しく処分していましたが、接続プーリングを使用していませんでした。
私の最初の検索 (たとえば、 thisおよびthis thread ) によると、ライブラリ自体に問題があるように見えました。オブジェクトが正しくリリースされていないか、プールの問題 (私は使用していません) のいずれかです。
あなたの質問を読んだ後、私は SQLiteCommand オブジェクトのみを使用して問題を再現しようとしましたが、それらを破棄しないと問題が発生することがわかりました。Update 2012-11-27 19:37 UTC : これはSystem.Data.SQLite のこのチケットによってさらに確認され、開発者は「接続に関連付けられたすべてのSQLiteCommand および SQLiteDataReader オブジェクトは適切に破棄される必要がある」と説明しています。
次に、生成された TableAdapters を元に戻すと、Dispose
メソッドの実装がないことがわかりました。つまり、実際には、作成されたコマンドは破棄されませんでした。すべてのコマンドを破棄して実装しましたが、問題はありません。
これがC#のコードです。これが役立つことを願っています。コードは元の Visual Basicから変換されるため、変換エラーが発生する可能性があることに注意してください。
//In Table Adapter
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Common.DisposeTableAdapter(disposing, _adapter, _commandCollection);
}
public static class Common
{
/// <summary>
/// Disposes a TableAdapter generated by SQLite Designer
/// </summary>
/// <param name="disposing"></param>
/// <param name="adapter"></param>
/// <param name="commandCollection"></param>
/// <remarks>You must dispose all the command,
/// otherwise the file remains locked and cannot be accessed
/// (for example, for reading or deletion)</remarks>
public static void DisposeTableAdapter(
bool disposing,
System.Data.SQLite.SQLiteDataAdapter adapter,
IEnumerable<System.Data.SQLite.SQLiteCommand> commandCollection)
{
if (disposing) {
DisposeSQLiteTableAdapter(adapter);
foreach (object currentCommand_loopVariable in commandCollection)
{
currentCommand = currentCommand_loopVariable;
currentCommand.Dispose();
}
}
}
public static void DisposeSQLiteTableAdapter(
System.Data.SQLite.SQLiteDataAdapter adapter)
{
if (adapter != null) {
DisposeSQLiteTableAdapterCommands(adapter);
adapter.Dispose();
}
}
public static void DisposeSQLiteTableAdapterCommands(
System.Data.SQLite.SQLiteDataAdapter adapter)
{
foreach (object currentCommand_loopVariable in {
adapter.UpdateCommand,
adapter.InsertCommand,
adapter.DeleteCommand,
adapter.SelectCommand})
{
currentCommand = currentCommand_loopVariable;
if (currentCommand != null) {
currentCommand.Dispose();
}
}
}
}
更新 2013-07-05 17:36 UTC gorogm の回答では、2 つの重要な点が強調されています。
System.Data.SQLite の公式サイトの変更ログによると、バージョン 1.0.84.0 以降では、ライブラリがこれを処理するため、上記のコードは必要ありません。私はこれをテストしていませんが、最悪の場合、このスニペットだけが必要です:
//In Table Adapter
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
this.Adapter.Dispose();
}
Dispose
の呼び出しの実装についてTableAdapter
: データセットの再生成がこのコード (および追加する必要がある追加のコード) に影響しないように、これを部分クラスに配置することをお勧めします。