I'm having a problem closing my database before an attempt to delete the file. The code is just
myconnection.Close();
File.Delete(filename);
And the Delete throws an exception that the file is still in use. I've re-tried the Delete() in the debugger after a few minutes, so it's not a timing issue.
I have transaction code but it doesn't run at all before the Close() call. So I'm fairly sure it's not an open transaction. The sql commands between open and close are just selects.
ProcMon shows my program and my antivirus looking at the database file. It does not show my program releasing the db file after the close().
Visual Studio 2010, C#, System.Data.SQLite version 1.0.77.0, Win7
I saw a two year old bug just like this but the changelog says it's fixed.
Is there anything else I can check? Is there a way to get a list of any open commands or transactions?
New, working code:
db.Close();
GC.Collect(); // yes, really release the db
bool worked = false;
int tries = 1;
while ((tries < 4) && (!worked))
{
try
{
Thread.Sleep(tries * 100);
File.Delete(filename);
worked = true;
}
catch (IOException e) // delete only throws this on locking
{
tries++;
}
}
if (!worked)
throw new IOException("Unable to close file" + filename);
In my case I was creating
SQLiteCommand
objects without explicitly disposing them.I wrapped my command in a
using
statement and it fixed my issue.Then it's a lot easier to execute commands as well.
Waiting for Garbage Collector may not release the database all time and that happened to me. When some type of Exception occurs in SQLite database for example trying to insert a row with existing value for PrimaryKey it will hold the database file until you dispose it. Following code catches SQLite exception and cancels problematic command.
If you not handle problematic commands' exceptions than Garbage Collector cannot do anything about them because there are some unhandled exceptions about these commands so they are not garbage. This handling method worked well for me with waiting for garbage collector.
Encountered the same problem a while ago while writing a DB abstraction layer for C# and I never actually got around to finding out what the issue was. I just ended up throwing an exception when you attempted to delete a SQLite DB using my library.
Anyway, this afternoon I was looking through it all again and figured I would try and find out why it was doing that once and for all, so here is what I've found so far.
What happens when you call
SQLiteConnection.Close()
is that (along with a number of checks and other things) theSQLiteConnectionHandle
that points to the SQLite database instance is disposed. This is done through a call toSQLiteConnectionHandle.Dispose()
, however this doesn't actually release the pointer until the CLR's Garbage Collector performs some garbage collection. SinceSQLiteConnectionHandle
overrides theCriticalHandle.ReleaseHandle()
function to callsqlite3_close_interop()
(through another function) this does not close the database.From my point of view this is a very bad way to do things since the programmer is not actually certain when the database gets closed, but that is the way it has been done so I guess we have to live with it for now, or commit a few changes to System.Data.SQLite. Any volunteers are welcome to do so, unfortunately I am out of time to do so before next year.
TL;DR The solution is to force a GC after your call to
SQLiteConnection.Close()
and before your call toFile.Delete()
.Here is the sample code:
Good luck with it, and I hope it helps
The following worked for me:
More info: Connections are pooled by SQLite in order to improve performance.It means when you call Close method on a connection object, connection to database may still be alive (in the background) so that next Open method become faster.When you known that you don't want a new connection anymore, calling ClearAllPools closes all the connections which are alive in the background and file handle(s?) to the db file get released.Then db file may get removed, deleted or used by another process.
I was having a similar problem, I've tried the solution with
GC.Collect
but, as noted, it can take a long time before the file becomes not locked.I've found an alternative solution that involves the disposal of the underlying
SQLiteCommand
s in the TableAdapters, see this answer for additional information.Just
GC.Collect()
didn't work for me.I had to add
GC.WaitForPendingFinalizers()
afterGC.Collect()
in order to proceed with the file deletion.