ServiceStack OrmLite and transactions - sql-server

I am trying to execute sql inside a transaction using ServiceStack OrmLite. The code below works with Sqlite but not with SqlServer. With SqlServer I get the following error:
ExecuteScalar requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
Is there something wrong with this code?
using (var trans = Db.BeginTransaction())
{
try
{
foreach (myObject in myObjects)
Db.Insert<MyObject>(myObject);
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}

Someone else put this answer in a comment and then deleted it... so:
BeginTransaction needs to be OpenTransaction

Related

Updating database using SubmitChanges

I'm trying to update a record in a database through C# code. I found a solution that I think should work using SaveChanges. However, I'm getting an error from my catch statement that says: "An error occurred while starting a transaction on the provider connection. See the inner exception for details." I'm either looking for an answer on how to fix it and/or how to make my catch statement give better details on what the problem actually is.
This is my code.
using var orderContext =
new OrderContext(Resources.SqlAuthenticationConnectionString);
foreach(OrderRecord order in orders)
{
var query =
from o in orderContext.OrderRecords
where o.ID == order.ID
select o;
foreach(OrderRecord record in query)
{
record.HeatLotNumber = order.HeatLotNumber;
record.OrderNumber = order.OrderNumber;
record.ShimCenterMaterial = order.ShimCenterMaterial;
try
{
orderContext.SaveChanges();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
Looks like I didn't look hard enough. Here's what my problem was. The save needs to be outside the foreach loop.
An error occurred while starting a transaction on the provider connection. See the inner exception for details

Executing a non-query requires a transaction

I migrated my code from WebApi2 to NET5 and now I have a problem when executing a non-query. In the old code I had:
public void CallSp()
{
var connection = dataContext.GetDatabase().Connection;
var initialState = connection.State;
try
{
if (initialState == ConnectionState.Closed)
connection.Open();
connection.Execute("mysp", commandType: CommandType.StoredProcedure);
}
catch
{
throw;
}
finally
{
if (initialState == ConnectionState.Closed)
connection.Close();
}
}
This was working fine. After I migrated the code, I'm getting the following exception:
BeginExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
So, just before calling Execute I added:
var ct = dataContext.GetDatabase().CurrentTransaction;
var tr = ct.UnderlyingTransaction;
And passed the transaction to Execute. Alas, CurrentTransaction is null, so the above change can't be used.
So then I tried to create a new transaction by doing:
using var tr = dataContext.GetDatabase.BeginTransaction();
And this second change throws a different exception complaining that SqlConnection cannot use parallel transactions.
So, now I'm in a situation where I originally had no problem to having neither an existing transaction nor can I create a new one.
How can I make Dapper happy again?
How can I make Dapper happy again?
Dapper has no opinion here whatsoever; what is unhappy is your data provider. It sounds like somewhere, somehow, your dataContext has an ADO.NET transaction active on the connection. I can't tell you where, how, or why. But: while a transaction is active on a connection, ADO.NET providers tend to be pretty fussy about having that same transaction explicitly specified on all commands that are executed on the connection. This could be because you are somehow sharing the same connection between multiple threads, or it could simply be that something with the dataContext has an incomplete transaction somewhere.

Why use a SqlTransaction object in ADO.NET C#?

I'm working on a WPF application in ADO.NET C#. I'm using a local database to do some test. My question is: Why should I use a Transaction before executing, for example, an UPDATE/INSERT command?
I've tried to do UPDATE and INSERT commands with SqlConnection, SqlCommand, SqlDataAdapter and they work well, even if I've never used a SqlTransaction object on the Connection object. If I do (on a Save Button):
try
{
conn.Open();
SqlTransaction sqlTran = conn.BeginTransaction(IsolationLevel.Serializable);
dAdapter.SelectCommand.Transaction = sqlTran;
dAdapter.Update(dtTable);
sqlTran.Commit();
conn.Close();
}
catch(Exception ex)
{
sqlTran.RollBack();
conn.Close();
}
what are the differences with the same instructions but without the transactions (and Commit/Rollback)?

ZombieCheck Exception - This SqlTransaction has completed; it is no longer usable -- during simple commit

I have the following code which performs a commit of a single row to a database table (SQL 2008 / .NET 4)
using (var db = new MyDbDataContext(_dbConnectionString))
{
Action action = new Action();
db.Actions.InsertOnSubmit(dbAction);
db.SubmitChanges();
}
Normally everything is fine, but once in a while I get the following exception:
System.InvalidOperationException: This SqlTransaction has completed; it is no longer usable.
at System.Data.SqlClient.SqlTransaction.ZombieCheck()
at System.Data.SqlClient.SqlTransaction.Rollback()
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
There are a number of similar questions on SO but I after reading them I cannot work out the cause.
Could this be simply due to a SQL timeout (the exception occurs close to 25s after the call is made)? Or should I expect a SQL timeout exception in that case?
Does anyone know what else may cause this?
The DataContext.SubmitChanges method has the following code lines in it's body:
// ...
try
{
if (this.provider.Connection.State == ConnectionState.Open)
{
this.provider.ClearConnection();
}
if (this.provider.Connection.State == ConnectionState.Closed)
{
this.provider.Connection.Open();
flag = true;
}
dbTransaction = this.provider.Connection.BeginTransaction(IsolationLevel.ReadCommitted);
this.provider.Transaction = dbTransaction;
new ChangeProcessor(this.services, this).SubmitChanges(failureMode);
this.AcceptChanges();
this.provider.ClearConnection();
dbTransaction.Commit();
}
catch
{
if (dbTransaction != null)
{
dbTransaction.Rollback();
}
throw;
}
// ...
When the connection times out, the catch block is executed and the dbTransaction.Rollback(); line will throw a InvalidOperationException.
If you had control over the code, you could catch the exception like this:
catch
{
// Attempt to roll back the transaction.
try
{
if (dbTransaction != null)
{
dbTransaction.Rollback();
}
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
throw;
}
YES! I had the same issue. The scary answer is that SQLServer sometimes rolls back a transaction on the server side when it encounters an error, and does not pass the error back to the client. YIKES!
Look on the Google Group microsoft.public.dotnet.framework.adonet for "SqlTransaction.ZombieCheck error" Colberd Zhou [MSFT] explains it very well.
and see aef123's comment on this SO post
May I suggest that connection closes earlier that transaction commits. Then the transaction is rolled back. Check this article on MSDN Blog.

java:not able to set auto commit mode with value false in java 1.4 api?

sql server 200
java 1.4
jboss 3
HI am getting exception message
"You cannot set autocommit during a managed transaction"
code is below
try {
try {
connection = getConnection();
} catch (Exception e) {
throw new ConnectionException(e.getMessage());
}
for(int i=0;i<recordIds.size();i++)
{
String currentRecordId=(String)recordIds.get(i);
try
{
//exception on this line connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(getSQL("PurgeRecordInDumpData"));
preparedStatement.setLong(1,Long.parseLong(currentRecordId));
int numberOfUpdates=preparedStatement.executeUpdate();
if(numberOfUpdates!=1)
{
throw new Exception("Record with record id "+currentRecordId +"could not be purged.");
}
preparedStatement.close();
connection.commit();
listOfPurgedRecords.add(currentRecordId);
}
catch(Exception e)
{
connection.rollback();
}
}
return listOfPurgedRecords;
}
what is cause of this exception and what does it mean?
The error is clear, you cannot set autocommit while you are in a managed transaction. You should not even need to set this to false as that is the default, you use to enable it autocommit.
I am not sure if you are using J2EE and EJB's, if you are and you want to ENABLE autocommit, you can change your setting to bean managed transaction (BMT) and this would allow you to modify this setting.
However, the way you are using it in your code you don't need to set it to false, everything is done in transactions and you control them with commit or rollback.

Resources