EFCore.BulkExtensions icon indicating copy to clipboard operation
EFCore.BulkExtensions copied to clipboard

Sqlite Exception: System.InvalidOperationException: SqliteConnection does not support nested transactions

Open d79ima opened this issue 3 years ago • 4 comments

I have a somewhat special use case in my EFCore application. When a DBContext is newed up i need it to re-use a SqliteConnection object from my own application connection pool instead of just allocating a new SqliteConnection every time.

This use case causes the following issue with EFCore.BulkExtensions. For example if we look at the code in SqlBulkOperation.cs Insert<T> method:

var transaction = (SqliteTransaction)(context.Database.CurrentTransaction == null ? connection.BeginTransaction() : context.Database.CurrentTransaction.GetUnderlyingTransaction(tableInfo.BulkConfig));

The call to connection.BeginTransaction() allocates a Transaction object and associates it with the connection object from the connection pool. If the sqlite operation happens to error out for some reason, the connection.Transaction is never cleared out. So all subsequent Bulk operations that execute the above code, created a nested transaction because context.Database.CurrentTransaction == null, So a new transaction is attempted on connection.BeginTransaction() and this throws the exception in the title of this issue.

Could you please review and suggest a workaround?

Also, in case an exception is thrown after we called BeginTransaction(), shouldn't we do a RollBackTransaction()?

d79ima avatar Jul 29 '21 18:07 d79ima

Best solution i could come up with so far is to add a catch clause and rollback the transaction only if we are doing explicitCommit: AddedCatchWIthRollBack

d79ima avatar Jul 29 '21 19:07 d79ima

Aside from nesting Bulk ops into a transaction scope, there is also Underlying-Conn/Tran. Note in ReadMe: Config also has DelegateFunc for setting Underlying-Connection/Transaction, e.g. in UnderlyingTest.

borisdj avatar Aug 03 '21 11:08 borisdj

Those might be reasonable workarounds, i would have to try them.

But I still think if the library creates its own transaction via connection.BeginTransaction() than it should be responsible for managing it. So if you are doing an explicit commit, should probably also do an explicit rollback and dispose. Is there any harm in including this extra code in a future version?

d79ima avatar Aug 03 '21 19:08 d79ima

I think your suggestion can be added, will consider it.

borisdj avatar Aug 03 '21 20:08 borisdj