且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

SQLite的保持甚至锁定数据库的连接关闭后

更新时间:2022-12-31 12:58:09

我不得不使用带有附带设计器生成数据集/ TableAdapter的同样的问题 System.Data.Sqlite.dll 1.0.82.0版本 - 关闭我们无法读取使用 System.IO.FileStream 数据库文件的连接之后。我是正确处理两者的连接和TableAdapter的,我并没有使用连接池。

I had the same problem using the datasets/tableadapters generated with the designer shipped with System.Data.Sqlite.dll version 1.0.82.0 -- after closing the connection we were unable to read the database file using System.IO.FileStream. I was disposing correctly both connection and tableadapters and I was not using connection pooling.

据我的第一个搜索(例如this和this这似乎在图书馆本身的问题线程) - 无论是对象不正确地释放和/或池的问题(我不使用)

According to my first searches (for example this and this thread) that seemed a problem in the library itself -- either objects not correctly released and/or pooling issues (which I don't use).

阅读您的问题后,我试图复制使用问题只SQLiteCommand对象,我发现,问题就出现了,当你不处理它们。 更新2012年11月27日19:37 UTC :这是由这对于System.Data.SQLite票,其中开发人员解释说,与连接相关联的所有的SQLiteCommand和SQLiteDataReader对象[应]妥善处理。

After reading your question I tried to replicate the problem using only SQLiteCommand objects and I found that the problem arises when you don't dispose them. Update 2012-11-27 19:37 UTC: this is further confirmed by this ticket for System.Data.SQLite, in which a developer explains that "all SQLiteCommand and SQLiteDataReader objects associated with the connection [should be] properly disposed".

我再重新打开生成的TableAdapter的,我看到,没有了的Dispose 方法的实现 - 所以其实创建的命令并未处理。我实现它,以处理所有的命令照顾,和我有没有问题。

I then turned back on the generated TableAdapters and I saw that there was no implementation of the Dispose method -- so in fact the created commands were not disposed. I implemented it, taking care of disposing all the commands, and I have got no problem.

下面是在C#中code,希望这有助于。请注意,code都在Visual Basic中中的原来的转换,所以我们期待一些转换错误。

Here's the code in C#, hope this helps. Please note that the code is converted from the original in Visual Basic, so expect some conversion errors.

//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年7月5日17:36 UTC gorogm的回答突出了两个重要的事情

Update 2013-07-05 17:36 UTC gorogm's answer highlights two important things:


  • 根据的changelog 在官方网站System.Data.SQLite,从版本1.0.84.0上述code首发应该没有必要,因为库会处理这件事。我没有测试过这一点,但在最坏的情况下,你只需要这个片段:

  • according to the changelog on the official site of System.Data.SQLite, starting from version 1.0.84.0 the above code should not be needed, since the library takes care of this. I haven't tested this, but in the worst case you only need this snippet:

//In Table Adapter    
protected override void Dispose(bool disposing)
{
  base.Dispose(disposing);

  this.Adapter.Dispose();
}


  • 有关的的TableAdapter 的Dispose 调用的实现:它是更好地把这个在部分类,让数据恢复不影响本code(以及任何额外的code,你可能需要添加)。

  • about the implementation of the Dispose call of the TableAdapter: it is is better to put this in a partial class, so that a dataset regeneration does not affected this code (and any additional code you may need to add).