Custom atomic UPDATE commands inside SaveChanges() - c#

For various reasons I need to be able to do several custom SQL UPDATE commands when I call SaveChanges on a DbContext. I want this to happen atomically so either both the regular SaveChanges and the SQL succeeds, or neither does.
I don't know how to accomplish this though. What I've tried so far is this and various variations:
EF transactions — Gist
The error here is (on the ExecuteSqlCommand call):
ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction.
Okay, fair enough. The ExecuteSqlCommand doesn't have an overload that accepts a transaction though. So, I installed the Dapper package and replaced the offending line with this Dapper call and I pass in the transaction:
this.Database.Connection
.Execute("insert into Tests (Foo, Bar) values ('test', 2)",
transaction: tran);
but now the error happens on base.SaveChanges() and it gives me the following:
SqlConnection does not support parallel transactions.
So apparently SaveChanges always creates a new transaction even though I created one on the connection of the datacontext already?
Is there any way in which I can accomplish what I want?
I'm using Entity Framework 5.0 Code First.

Wrap a TransactionScope around all operations. This class is the common abstraction for .NET transactions. EF and SqlConnection's will enlist automatically. Be sure to look for best-practices though as there are some pitfalls like accidentally triggering distributed transactions.

Related

Why does Dapper need a reference to the transaction when executing a query?

Just looking through this tutorial: https://www.davepaquette.com/archive/2019/02/06/managing-transactions-in-dapper.aspx
My understanding (without Dapper) is once you have a connection, you can open a transaction, then execute a bunch of statements, then either commit or roll back the transaction. Those queries don't need to reference the transaction because the connection already 'knows' about it.
So why does Dapper need the transaction every time some action is performed?
Dapper doesn't change anything about the fundamental ADO.NET model, so if your operation inside a transaction fails if you don't explicitly pass the transaction to Dapper, then that is an ADO.NET thing, and the same operation would fail in exactly the same way without Dapper. All Dapper does is set the Transaction property on the command.
Or to put it another way: I believe your understanding is incorrect here. I agree with you that your understanding and expectation is reasonable though, and I'm not aware of any good reason that the command should even need to know about the transaction, which is ultimately a connection concern. But: I don't make the rules :/
Note that it is possible to use a "decorator" pattern in ADO.NET (mini-profiler does this, for example), so in theory it would be possible to create a connection wrapper that tracks the transaction for you, and have the command retrieve the transaction and attach it automatically when operations are performed. It probably isn't much work if you start from mini-profiler's base type.

TransactionScope transaction = new TransactionScope() VS TransactionScope s = context.Connection.BeginTransaction()

I just want to know if I want to rollback all changes in database if transaction not complete, is there any difference between
using (TransactionScope transaction = new TransactionScope())
and
using (var dbContextTransaction = context.Database.BeginTransaction())
I am confused when read these two:
Connection.BeginTransaction and Entity Framework 4?
and
https://learn.microsoft.com/en-us/ef/ef6/saving/transactions
**note that I use entity framework 4 in my project if its necessary
From Programming Microsoft SQL Server 2012:
There are a number of pain points with explicit transactions. The first difficulty lies in the requirement that every SqlCommand object used to perform updates inside the transaction must have its Transaction property set to the SqlTransaction object returned by BeginTransaction. This means that you must take care to pass along the SqlTransaction object to any place in your code that performs an update, because failing to assign it to the Transaction property of every SqlCommand object in the transaction results in a runtime exception. The issue is compounded when you need to track the SqlTransaction object across multiple method calls that perform updates. It becomes even harder to manage things when these methods need to be flexible enough to work whether or not a transaction is involved or required.
The problem is worse when working with any of the other technologies we'll be covering later that provide abstraction layers over the raw objects. For example, because a SqlDataAdapter actually wraps three distinct SqlCommand objects (for insert, update, and delete), you must dig beneath the data adapter and hook into its three underlying command objects so that you can set their Transaction properties. (We don't generally recommend that you mix and match different data access APIs within your application, but if you must transactionalize updates across a combination of technologies, implicit transactions make it easy.)
The TransactionScope object, introduced as part of a dedicated transaction management API with .NET 2.0 in 2005, lets you code transactions implicitly. This is a superior approach that relieves you from all of the aforementioned burdens associated with explicit transactions. So the guidance here is to always work with implicit transactions whenever possible. You will write less code that is more flexible when you allow the framework to handle transaction management for you. However, it is still also important to understand explicit transactions with the SqlTransaction object, as you might need to integrate with and extend existing code that already uses explicit transactions. Therefore, we will cover both transaction management styles to prepare you for all situations.
The transaction management API offers many more benefits besides implicit transactions. For example, TransactionScope is capable of promoting a lightweight transaction (one associated with a single database) to a distributed transaction automatically, if and when your updates involve changes across multiple databases.
There are two pitfalls with TransactionScope you should be aware of.
First is that it will, by default, create a transaction with SERIALIZABLE isolation level, which, for SQL Server, is a poor choice. So you should always create your TransactionScope like this:
public class TransactionUtils
{
public static TransactionScope CreateTransactionScope()
{
var transactionOptions = new TransactionOptions();
transactionOptions.IsolationLevel = IsolationLevel.ReadCommitted;
transactionOptions.Timeout = TransactionManager.MaximumTimeout;
return new TransactionScope(TransactionScopeOption.Required, transactionOptions);
}
}
See rant here: using new TransactionScope() Considered Harmful
The second is that TransactionScope supports Distributed Transactions. So it will enable you to enlist different connections and even different resource providers in a single transaction. While this is occasionally useful, it's more often a pitfall. If you accidently end up with a distributed transaction you can accidently take a dependency on having a distributed transaction coordinator in your environment. So you should take steps to avoid having a distributed transaction, like shutting down Microsoft Distributed Transaction Coordinator (MSDTC) in your development environment. And ensure that any time you have multiple methods enlisted in a transaction, they don't both have a SqlConnection open at the same time.
While Database. BeginTransaction() is used only for database related operations transaction, System. Transactions. ... TransactionScope for mixing db operations and C# code together in a transaction.
please see Below Links.Hope they help you:
TransactionScope vs Transaction in LINQ to SQL
Database.BeginTransaction vs Transactions.TransactionScope

Rollback changes made to Database in Entity Framework .NET

I am writing unit test cases for testing a framework. The unit test adds and modifies the data in an existing database. I need to rollback all the changes done to database after a test finishes, i.e. delete the rows added and revert the rows modified.
I am using Entity Framework 6 for accessing the database. The underlying database is SQL Server. Is there any support provided by EF6 to achieve this?
Presently I am storing the changes in a list and I refer the this list for cleaning up the database. But using this approach leaves some residue randomly. I am not sure of the reason though, maybe some race condition or something.
Looking for some minimal and smart alternative for it. Thanks in advance :)
you can wrap your test in a transaction and don't commit changes:
using (TransactionScope scope = new TransactionScope()) {
//do your stuff
}
But for unit testing propouses you can use Effort - Entity Framework Unit Testing Tool which provide in-memory database operations.
EDITED to reply last comments
You can use an overloaded TransactionScope contructor to control the IsolationLevel, so you can choose to read uncommited changes or not.
If your proxy isn't inside the Transaction, please, check that the connection string is the same, so ado.net can identify the connection and enlist the connection in the same transaction.
If the connection string is not the same, you probably will need to activate the Distributed Transaction Coordinator. Here you have an explanation how DTC scalation occurs: TransactionScope automatically escalating to MSDTC on some machines?

Entity Framework: Controlling db connection and specifying own transaction

I want to find a way to control EF's underlying db connection & transaction to make sure my application is using only one connection at a time during one transaction (I will need to support both Oracle and SQL Server).
I found this good article which comes with a lot of recommendations, but brings up (like all the other articles I have read) the TransactionScope. Well, I would like to stay away of TransactionScope, if possible...
Could I have a solution for this playing with only pure DbConnection & DbTransaction or this is simply impossible or wrong?
Even more, I found this article here, stating at section :
"Specifying Your Own Transaction"
Just as you can override the default behavior with connections, you
can also control transaction functionality. If you explicitly create
your own transaction, SaveChanges will not create a DbTransaction. You
won't create a System.Common.DbTransaction, though. Instead, when
creating your own transactions, you need to use a
System.Transaction.TransactionScope object.
But there is no explaination...
I am using Entity Framework 5.0. Could you please help me understand in order to choose correct for my application? It would be ideal to show me some good patterns of usage.
Thanks in advance!
Note: I am planning this because of the transactions escalating to DTC for Oracle Data Provider.
Entity Framework 6 has two features which may help with this:
Explicit Transaction Support
Ability to create a DbContext from a DbConnection.
If you did want to use EF5, you'd need to use a TransactionScope:
var context = new MyContext();
using (var transaction = new TransactionScope())
{
MyItem item = new MyItem();
context.Items.Add(item);
context.SaveChanges();
item.Name = "Edited name";
context.SaveChanges();
transaction.Complete();
}
As mentioned in the linked article, you will need to reference System.Transactions to get TransactionScope.
Entity Framework maintains its own transaction which is sufficient. However it gives you flexibility of committing or discarding the changes in transaction. If you do not call SaveChanges() method then it will discard the transaction. Also if you are using the same DbContext for many transactions, then it would be using same connection. If you use two or more DbContext at the same time, then it will use separate connections which is ideal situation. Here is a very important point I would like to make is that it would be a waste of Entity Framework technology to implement own transaction. If you want to do so, then I would suggest to use your own DB implementation in traditional way.

How to check if i am in a transaction?

I have a piece of code i recently expanded but now must use a transaction. It looks like it can only be access while in a transaction but looks like doesnt make me feel comfortable. Using SQLite and ADO.NET i wrote if(cmd.Transaction==null) but it is null and in a transaction. How should i check?
NOTE: I will be using this code with TSQL in the future. This is a quick prototype with SQLite
-edit- i was thinking of nesting transactions but this code generates a piece of sql and uses a command to add parameters too. So adding a nested transaction would take a lot of modification.
Depending on the nature of the SQL and its fit in the application, it may be more appropriate for you to nest transactions, ensuring a transaction is present regardless of the context of the call.
For example, you could wrap the calling code in a TransactionScope block. If there is a transaction present, this will have no real effect on the operation. If there is no transaction present, it will create a transaction and ensure the ADO.NET code participates in the transaction.
This approach only works if you're happy for the SQL to be executed as a single operation. If it should only be called as part of a larger transaction, this approach doesn't help.
To know for sure that a transaction is present, you have to check for the explicit transaction on the ADO.NET command (as you have above) and also the presence of an ambient transaction from the System.Transactions programming model using the Transaction.Current property.

Categories