I'm getting locking exceptions when trying to use transactions with SubSonic and SQLite. I'm using this from a single thread and there are no other processes accessing my db, so I really didn't expect any such problems.
If I write code like this below, I get an exception on the second call to Save() within the loop - so the third call to Save() over all.
using (TransactionScope ts = new TransactionScope())
{
using (SharedDbConnectionScope sharedConnectinScope = new SharedDbConnectionScope())
{
SomeDALObject x = new SomeDALObject()
x.Property1 = "blah";
x.Property2 = "blah blah";
x.Save();
foreach (KeyValuePair<string, string> attribute in attributes)
{
AnotherDALObject y = new AnotherDALObject()
y.Property1 = attribute.Key
y.Property2 = attribute.Value
y.Save(); // this is where the exception is raised, on the 2nd time through this loop
}
}
}
If I have the using() statements as above, or if I just have using (TransactionScope ts = new TransactionScope())
then I get a System.Data.SQLite.SQLiteException
with message
The database file is locked
database is locked
The stack trace is:
at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock)
at System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.SQLite.SQLiteConnection.BeginTransaction()
at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
at System.Data.SQLite.SQLiteConnection.Open()
at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString)
at SubSonic.SQLiteDataProvider.CreateConnection()
at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry)
at SubSonic.DataService.ExecuteScalar(QueryCommand cmd)
at SubSonic.ActiveRecord`1.Save(String userName)
at SubSonic.ActiveRecord`1.Save()
at (my line of code above).
If I have the using statments nested the other way around, with SharedDbConnectionScope on the outside, then I get a TransactionException
with message "The operation is not valid for the state of the transaction." Stack trace is:
at System.Transactions.TransactionState.EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
at System.Transactions.Transaction.EnlistVolatile(IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
at System.Data.SQLite.SQLiteConnection.Open()
at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString)
at SubSonic.SQLiteDataProvider.CreateConnection()
at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry)
at SubSonic.DataService.ExecuteScalar(QueryCommand cmd)
at SubSonic.ActiveRecord`1.Save(String userName)
at SubSonic.ActiveRecord`1.Save()
at (my line of code above)
and the inner exception is "Transaction Timeout"
I don't have any custom code in my generated DAL classes, or anything else clever that I can think of that would be causing this.
Anyone else encountered transaction problems like this or can someone suggest where I start looking for the problem?
thanks!
UPDATE: I notice mention of transaction-related things in the release notes for versions 1.0.61-65 (e.g. here), so perhaps updating SubSonic to work with the latest version of the .Net Data Provider would solve some of these issues...