Executing a non-query requires a transaction - sql-server

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.

Related

Transaction scope issue in Entity Framework

Transaction associated with the current connection has completed but has not been disposed. Transaction must be disposed before the connection can be used to execute SQL statements
I am getting the above error, when I try to save through EF6 in a transaction.
I am updating data in a table and I have a trigger on update for that table. So, when I disable the trigger everything works fine, but when I enable the trigger I get the above mentioned error.
I tried increasing timeout and suppressing the transaction, but no luck..
My transaction code looks like this:
using (TransactionScope transaction = new TransactionScope())
{
var obj = this._objRepo.GetobjCodesByName("xxxxxx");
obj.CodeName = "eeee";
this._context.SaveChanges();
transaction.Complete();
return Code;
}
Any workaround?
Here you don't need to use Transaction at all.B'cos you have only one transaction.Then you don't need to use TransactionScope().If you use it unnecessary,it'll give extra overhead to your saving process.In other words it causes to slowdown the operation.
You can try as shown below without using TransactionScope().
using (var _context= new YourDBEntities())
{
//your update code
_context.SaveChanges();
}
I dont know the full scope of the code. But based on the code snippet posted in your question, the problem is at _objRepo.GetobjCodesByName("xxxxxx");
You need to suppress your selects from transaction scope. In SQL Server 2005 and above, even when you use with(nolock), locks are still created on those tables the select touches.
To address this situation, you need to rewrite the code as below
using (TransactionScope transaction = new TransactionScope())
{
using(TransactionScope tsSuppressed = new TransactionScope(TransactionScopeOption.Suppress))
{
var obj = this._objRepo.GetobjCodesByName("xxxxxx");
obj.CodeName = "eeee";
}
this._context.SaveChanges();
transaction.Complete();
return Code;
}
Hope this helps.

Does the SQL connection not get closed if you put the datareader in a using block?

So, I recently inherited a large project that uses the following data access pattern; unfortunately, this is resulting in a massive number of timeout exceptions related to connection pooling.
Timeout expired. The timeout period elapsed prior to obtaining a
connection from the pool. This may have occurred because all pooled
connections were in use and max pool size was reached"
It clear that the connections are leaking and not getting closed properly.
So, the framework has a DataAccess class with the method GetDataReader.
When the data reader is referenced, it is placed inside a using block, but connections are still leaking.
Does the fact that the connection is not explicitly closed or placed in a using block the reason why the connections are getting leaked?
Normally, I would wrap the connection in a using block AND wrap the data reader in a using block.
Obviously, this framework is very flawed, but would somehow using the option CommandBehavior.CloseConnection for the data reader resolve this issue?
None the external code accesses the SqlConnection directly and has to go through this DataAccess class.
public IDataReader GetDataReader(QueryDto dto)
{
DateTime current = DateTime.Now;
Database db = DatabaseFactory.CreateDatabase(dto.DatabaseName);
DbCommand cmd = db.GetStoredProcCommand(dto.StoredProcedureName);
if (dto.Params.Length > 0)
{
cmd = db.GetStoredProcCommand(dto.StoredProcedureName, dto.Params);
}
dto.Command = cmd;
cmd.CommandTimeout = dto.Timeout;
cmd.Connection = db.CreateConnection();
try
{
cmd.Connection.Open();
}
catch (SqlException ex)
{
// Handle Exception here...
throw;
}
return rdr;
}
Usage in some static repository class:
var query = new QueryDto
{
DatabaseName = "SomeDatabase",
Params = parms,
StoredProcedureName = "StoredProcedureName"
};
using (IDataReader dr = dataAccess.GetDataReader(query))
{
while (dr.Read())
{
// do stuff here
}
}
I think your problem is that the using statement is around a function that has open resources embedded in it. The using will not dispose of the connection that is opened inside GetDataReader. I think your are correct that the Connection itself needs to be in a using block. The using statement only calls Dispose on the object that is passed in, not any nested resources.

"Cannot drop database because it is currently in use". How to fix?

Having this simple code I get "Cannot drop database "test_db" because it is currently in use" (CleanUp method) as I run it.
[TestFixture]
public class ClientRepositoryTest
{
private const string CONNECTION_STRING = "Data Source=.;Initial Catalog=test_db;Trusted_Connection=True";
private DataContext _dataCntx;
[SetUp]
public void Init()
{
Database.SetInitializer(new DropCreateDatabaseAlways<DataContext>());
_dataCntx = new DataContext(CONNECTION_STRING);
_dataCntx.Database.Initialize(true);
}
[TearDown]
public void CleanUp()
{
_dataCntx.Dispose();
Database.Delete(CONNECTION_STRING);
}
}
DataContext has one property like this
public DbSet<Client> Clients { get; set; }
How can force my code to remove database?
Thanks
The problem is that your application probably still holds some connection to the database (or another application holds connection as well). Database cannot be deleted where there is any other opened connection. The first problem can be probably solved by turning connection pooling off (add Pooling=false to your connection string) or clear the pool before you delete the database (by calling SqlConnection.ClearAllPools()).
Both problems can be solved by forcing database to delete but for that you need custom database initializer where you switch the database to single user mode and after that delete it. Here is some example how to achieve that.
I was going crazy with this! I have an open database connection inside SQL Server Management Studio (SSMS) and a table query open to see the result of some unit tests. When re-running the tests inside Visual Studio I want it to drop the database always EVEN IF the connection is open in SSMS.
Here's the definitive way to get rid of Cannot drop database because it is currently in use:
Entity Framework Database Initialization
The trick is to override InitializeDatabase method inside the custom Initializer.
Copied relevant part here for the sake of good DUPLICATION... :)
If the database already exist, you may stumble into the case of having
an error. The exception “Cannot drop database because it is currently
in use” can raise. This problem occurs when an active connection
remains connected to the database that it is in the process of being
deleted. A trick is to override the InitializeDatabase method and to
alter the database. This tell the database to close all connection and
if a transaction is open to rollback this one.
public class CustomInitializer<T> : DropCreateDatabaseAlways<YourContext>
{
public override void InitializeDatabase(YourContext context)
{
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction
, string.Format("ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", context.Database.Connection.Database));
base.InitializeDatabase(context);
}
protected override void Seed(YourContext context)
{
// Seed code goes here...
base.Seed(context);
}
}
This is a really aggressive database (re)initializer for EF code-first with migrations; use it at your peril but it seems to run pretty repeatably for me. It will;
Forcibly disconnect any other clients from the DB
Delete the DB.
Rebuild the DB with migrations and runs the Seed method
Take ages! (watch the timeout limit for your test framework; a default 60 second timeout might not be enough)
Here's the class;
public class DropCreateAndMigrateDatabaseInitializer<TContext, TMigrationsConfiguration>: IDatabaseInitializer<TContext>
where TContext: DbContext
where TMigrationsConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<TContext>, new()
{
public void InitializeDatabase(TContext context)
{
if (context.Database.Exists())
{
// set the database to SINGLE_USER so it can be dropped
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
// drop the database
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
}
var migrator = new MigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration>();
migrator.InitializeDatabase(context);
}
}
Use it like this;
public static void ResetDb()
{
// rebuild the database
Console.WriteLine("Rebuilding the test database");
var initializer = new DropCreateAndMigrateDatabaseInitializer<MyContext, MyEfProject.Migrations.Configuration>();
Database.SetInitializer<MyContext>initializer);
using (var ctx = new MyContext())
{
ctx.Database.Initialize(force: true);
}
}
I also use Ladislav Mrnka's 'Pooling=false' trick, but I'm not sure if it's required or just a belt-and-braces measure. It'll certainly contribute to slowing down the test more.
None of those solutions worked for me. I ended up writing an extension method that works:
private static void KillConnectionsToTheDatabase(this Database database)
{
var databaseName = database.Connection.Database;
const string sqlFormat = #"
USE master;
DECLARE #databaseName VARCHAR(50);
SET #databaseName = '{0}';
declare #kill varchar(8000) = '';
select #kill=#kill+'kill '+convert(varchar(5),spid)+';'
from master..sysprocesses
where dbid=db_id(#databaseName);
exec (#kill);";
var sql = string.Format(sqlFormat, databaseName);
using (var command = database.Connection.CreateCommand())
{
command.CommandText = sql;
command.CommandType = CommandType.Text;
command.Connection.Open();
command.ExecuteNonQuery();
command.Connection.Close();
}
}
I try adding Pooling=false like Ladislav Mrnka said but always got the error.
I'm using Sql Server Management Studio and even if I close all the connection, I get the error.
If I close Sql Server Management Studio then the Database is deleted :)
Hope this can helps
I got the same error. In my case, I just closed the connection to the database and then re-connected once the in my case the new model was added and a new controller was scaffolded. That is however a very simple solution and not recommended for all scenarios if you want to keep your data.
I got the same problem back then. Turns out the solution is to close the connection in Server Explorer tab in Visual Studio. So maybe you could check whether the connection is still open in the Server Explorer.
Its simple because u're still using the same db somewhere, or a connection is still open.
So just execute "USE master" first (if exist, but usually is) and then drop the other db. This always should work!
Grz John

SubSonic - Need to manually force connections closed?

In using Enterprise Library, there was an issue with having to manually close db connections, as GC, when scanning the heap, looks for items out of scope.
A connection that is part of a pool that is being used but the connection state is broken or fetching, but you have already received your results, will be kept open, and connection handles in the pool will run out.
Thus, adding manual connection checking and forcedly closing the connections is good form.
Now, take SubSonic. With an EntLib base, I am doing the following in a finally block:
public static bool GetISOCountryCodes(out DataSet dsISOCountryCodes, out Response dbResponse)
{
dbResponse = new Response();
dsISOCountryCodes = new DataSet();
StoredProcedure sp = null;
try
{
sp = SPs.GetISOCountryCodes(null);
dsISOCountryCodes = sp.GetDataSet();
// set the response object properties
dbResponse = new Response((int)sp.OutputValues[0]);
return dbResponse.IsValid;
}
catch (System.Exception ex)
{
return dbResponse.IsValid;
}
finally
{
if (sp.Command != null && sp.Command.ToDbCommand().Connection != null &&
sp.Command.ToDbCommand().Connection.State == ConnectionState.Open)
sp.Command.ToDbCommand().Connection.Close();
}
}
I know it's been said that you don't have to manually do this, as SubSonic will do this for you, however, I'd like to know if anyone has run into issues with SubSonic not closing connections (once again, as it uses EntLib at the root), and if there are better ways of accomplishing this.
Obviously, in all my data caller methods, I will reference one, say, "ConnectionCloser()" method.
Thanks.
This post was more of a notification for discussion. However, I'm not sure if the issue has actually been resolved with v5. So essentially the answer is to continue checking in the finally block.

How do I do nested transactions in NHibernate?

Can I do nested transactions in NHibernate, and how do I implement them? I'm using SQL Server 2008, so support is definitely in the DBMS.
I find that if I try something like this:
using (var outerTX = UnitOfWork.Current.BeginTransaction())
{
using (var nestedTX = UnitOfWork.Current.BeginTransaction())
{
... do stuff
nestedTX.Commit();
}
outerTX.Commit();
}
then by the time it comes to outerTX.Commit() the transaction has become inactive, and results in a ObjectDisposedException on the session AdoTransaction.
Are we therefore supposed to create nested NHibernate sessions instead? Or is there some other class we should use to wrap around the transactions (I've heard of TransactionScope, but I'm not sure what that is)?
I'm now using Ayende's UnitOfWork implementation (thanks Sneal).
Forgive any naivety in this question, I'm still new to NHibernate.
Thanks!
EDIT: I've discovered that you can use TransactionScope, such as:
using (var transactionScope = new TransactionScope())
{
using (var tx = UnitOfWork.Current.BeginTransaction())
{
... do stuff
tx.Commit();
}
using (var tx = UnitOfWork.Current.BeginTransaction())
{
... do stuff
tx.Commit();
}
transactionScope.Commit();
}
However I'm not all that excited about this, as it locks us in to using SQL Server, and also I've found that if the database is remote then you have to worry about having MSDTC enabled... one more component to go wrong. Nested transactions are so useful and easy to do in SQL that I kind of assumed NHibernate would have some way of emulating the same...
NHibernate sessions don't support nested transactions.
The following test is always true in version 2.1.2:
var session = sessionFactory.Open();
var tx1 = session.BeginTransaction();
var tx2 = session.BeginTransaction();
Assert.AreEqual(tx1, tx2);
You need to wrap it in a TransactionScope to support nested transactions.
MSDTC must be enabled or you will get error:
{"Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool."}
As Satish suggested, nested transactions are not supported in NHibernate. I've not come across scenarios where nested transactions were needed, but certainly I've faced problems where I had to ignore creating transactions if other ones were already active in other units of work.
The blog link below provides an example implementation for NHibernate, but should also work for SQL server:
http://rajputyh.blogspot.com/2011/02/nested-transaction-handling-with.html
I've been struggling with this for a while now. Am going to have another crack at it.
I want to implement transactions in individual service containers - because that makes them self-contained - but then be able to nest a bunch of those service methods within a larger transaction and rollback the whole lot if necessary.
Because I'm using Rhino Commons I'm now going to try refactoring using the With.Transaction method. Basically it allows us to write code as if transactions were nested, though in reality there is only one.
For example:
private Project CreateProject(string name)
{
var project = new Project(name);
With.Transaction(delegate
{
UnitOfWork.CurrentSession.Save(project);
});
return project;
}
private Sample CreateSample(Project project, string code)
{
var sample = new Sample(project, code);
With.Transaction(delegate
{
UnitOfWork.CurrentSession.Save(sample);
});
return sample;
}
private void Test_NoNestedTransaction()
{
var project = CreateProject("Project 1");
}
private void TestNestedTransaction()
{
using (var tx = UnitOfWork.Current.BeginTransaction())
{
try
{
var project = CreateProject("Project 6");
var sample = CreateSample(project, "SAMPLE006", true);
}
catch
{
tx.Rollback();
throw;
}
tx.Commit();
}
}
In Test_NoNestedTransaction(), we are creating a project alone, without the context of a larger transaction. In this case, in CreateSample a new transaction will be created and committed, or rolled back if an exception occurs.
In Test_NestedTransaction(), we are creating both a sample and a project. If anything goes wrong, we want both to be rolled back. In reality, the code in CreateSample and CreateProject will run just as if there were no transactions at all; it is entirely the outer transaction that decides whether to rollback or commit, and does so based on whether an exception is thrown. Really that's why I'm using a manually created transaction for the outer transaction; so we I have control over whether to commit or rollback, rather than just defaulting to on-exception-rollback-else-commit.
You could achieve the same thing without Rhino.Commons by putting a whole lot of this sort of thing through your code:
if (!UnitOfWork.Current.IsInActiveTransaction)
{
tx = UnitOfWork.Current.BeginTransaction();
}
_auditRepository.SaveNew(auditEvent);
if (tx != null)
{
tx.Commit();
}
... and so on. But With.Transaction, despite the clunkiness of needing to create anonymous delegates, does that quite conveniently.
An advantage of this approach over using TransactionScopes (apart from the reliance on MSDTC) is that there ought to be just a single flush to the database in the final outer-transaction commit, regardless of how many methods have been called in-between. In other words, we don't need to write uncommitted data to the database as we go, we're always just writing it to the local NHibernate cache.
In short, this solution doesn't offer ultimate control over your transactions, because it doesn't ever use more than one transaction. I guess I can accept that, since nested transactions are by no means universally supported in every DBMS anyway. But now perhaps I can at least write code without worrying about whether we're already in a transaction or not.
That implementation doesn't support nesting, if you want nesting use Ayende's UnitOfWork implementation. Another problem with the implementation your are using (at least for web apps) is that it holds onto the ISession instance in a static variable.
I just rewrote our UnitOfWork yesterday for these reasons, it was originally based off of Gabriel's.
We don't use UnitOfWork.Current.BeginTransaction(), we use UnitofWork.TransactionalFlush(), which creates a separate transaction at the very end to flush all the changes at once.
using (var uow = UnitOfWork.Start())
{
var entity = repository.Get(1);
entity.Name = "Sneal";
uow.TransactionalFlush();
}

Resources