views:

730

answers:

4

I'm using asp.net c# and upload a SqLite database to a server and then I do some inserting and updating. The problem is that sometimes (I think it's when somethings go wrong with the updating or so) the database gets locked. So the next time I try to upload a file again it's locked and I get an error saying "The process cannot access the file because it is being used by another process". Maybe the database file isn't disposed if something goes wrong during the transaction? The only thing to solve this problem is restarting the server.

How can I solve it in my code so I can be sure it's always unlocked even if something goes wrong?

This is my code:

try
{
  string filepath = Server.MapPath("~/files/db.sql");

  //Gets the file and save it on the server
  ((HttpPostedFile)HttpContext.Current.Request.Files["sqlitedb"]).SaveAs(filepath);

  //Open the database
  SQLiteConnection conn = new SQLiteConnection("Data Source=" + filepath + ";Version=3;");

  conn.Open();
  SQLiteCommand cmd = new SQLiteCommand(conn);
  using (SQLiteTransaction transaction = conn.BeginTransaction())
  {
     using (cmd)
     {
        //Here I do some stuff to the database, update, insert etc
     }
     transaction.Commit();
  }
  conn.Close();
  cmd.Dispose();
}
catch (Exception exp)
{
//Error
}
+1  A: 

You could try placing the Connection in a using block as well, or calling Dispose on it:

//Open the database
using (SQLiteConnection conn = new SQLiteConnection("Data Source=" + filepath + ";Version=3;")) {
  conn.Open();
  using (SQLiteCommand cmd = new SQLiteCommand(conn)) {
    using (SQLiteTransaction transaction = conn.BeginTransaction()) {
      //Here I do some stuff to the database, update, insert etc
      transaction.Commit();
    }
  }
}

This will ensure that you're disposing of the connection object's correctly (you're not at the moment, only closing it).

Wrapping them in using blocks ensures that Dispose is called even if an exception happens - it's effectively the same as writing:

// Create connection, command, etc objects.
SQLiteConnection conn;

try {
  conn = new SQLiteConnection("Data Source=" + filepath + ";Version=3;");
  // Do Stuff here...
}
catch (exception e) {
  // Although there are arguments to say don't catch generic exceptions,
  // but instead catch each explicit exception you can handle.
}
finally {
  // Check for null, and if not, close and dispose
  if (null != conn)
    conn.Dispose();
}

The code in the finally block is going to be called regardless of the exception, and helps you clean up.

Zhaph - Ben Duguid
Thanks!!If I use: "throw e;" in my catch will the finally part still run before it throws back the exception?
Yes: http://msdn.microsoft.com/en-us/library/xhcbs8fz.aspx
Zhaph - Ben Duguid
A: 

Shouldn't you do cmd.Dispose() before conn.Close()? I don't know if it makes any difference, but you generally want to clean things up in the opposite of initialization order.

Tim Sylvester
A: 

In short, SQLite handles unmanaged resources slightly differently than other providers. You'll have to explicitly dispose the command (which seems to work even if you are working with the reader outside of the using() block.

Read this thread for more flavor: http://sqlite.phxsoftware.com/forums/p/909/4164.aspx

Doug
A: 

An asp.net application is multithreaded in the server.

You can't do simultaneous writing (insert, select, update...) because the whole db is locked. Simultaneously selecting is allowed when no writing is happening.

You should use the .NET ReaderWriterLock class: http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx

tuinstoel