Is there anyway to find if a DbContext is enlisted in any transaction while enlist=false in the connection string?
I was tracing DbContext.Database.CurrentTransaction, but I noticed it is always null.
I know when enlist=false, all opened connections will not enlist themselves in an ambient transaction, is that right?
If (2) is correct, how to enlist DbContext in an transaction where TransactionScope is used?
Finally, I noticed using clones of DependentTransaction with multiple DbContext and multiple threads while enlist=false will not promote the transaction to distributed one, but I wonder am I still able to commit and rollback in case an exception happened using the dependent transaction while enlist=false?
if (4) is incorrect, then is there any way to fully avoid DistributedTransaction while being able to open multiple connections with a single transaction scope?
FYI, currently Oracle database is employed; however, in future MySQL is going to be in operation as well.
Thank you
I cant really say something to 1 , 2 and 3.. But:
The distribution-thing is not absolutely clear to me. But however, MS escalates Transactions from LTM (Lightweigt Transaction Manger) to DTC if a some criteria come to play. For Example if you try to access different databases in one transaction..
The escalation from LTM to DTC or the decission if an escalation will be forced is a system-decission. Until now I didnt find a way to change this behaviour. Thats why you need to think about the transactions in general. If there is a possibility to avoid multiple-database access you may rethink your transactions.
For further information I´ll recommend Why is my TransactionScope trying to use MSDTC when used in an EF Code First app? , MSSQL Error 'The underlying provider failed on Open' and How do I use TransactionScope in C#?
Related
I am stuck using two db connections with entity framework contexts under a single transaction.
I am trying to use two db contexts under one transaction scope. I get "MSTDC not available". I read it's not an EF problem it's TDC which does not allow two connections.
Is there any answer for this problem?
This happens because the framework thinks that you are trying to have a transaction span multiple databases. This is called a distributed transaction.
To use distributed transactions, you need a transaction coordinator. In your case, the coordinator is the Microsoft Distributed Transaction Coordinator, which runs as a Widows Service on your server. You will need to make sure that this service is running:
Starting the service should solve your immediate issue.
Two-phase commit
From a purely theoretical point of view, distributed transactions are an impossibility* - that is, disparate systems cannot coordinate their actions in such a way that they can be absolutely certain that they either all commit or all roll back.
However, using a transaction coordinator, you get pretty darn close (and 'close enough' for any conceivable purpose). When using a distributed transaction, each party in the transaction will try to make the required changes and report back to the coordinator whether all went well or not. If all parties report success, the coordinator will tell all parties to commit. However, if one or more parties report a failure, the coordinator will tell all parties to roll back their changes. This is the "Two-phase commit protocol".
Watch out
It obviously takes time for the coordinator to communicate with the different parties of the transaction. Thus, using distributed transactions can hamper performance. Moreover, you may experience blocking and deadlocking among your transactions, and MSDTC obviously complicates your infrastructure.
Thus, before you turn on the Distributed Transaction Coordinator service and forge ahead with your project, you should first take a long, hard look at your architecture and convince yourself that you really need to use multiple contexts.
If you do need multiple contexts, you should investigate whether you can prevent transactions from being escalated to distributed transactions.
Further reading
You may want to read:
MSDN: "Managing Connections and Transactions" (specifically on EF)
Blog: "Avoid unwanted escalation to distributed transactions" (a bit dated, though)
***** See for example: Reasoning About Knowledge
You should run MSDTC (Distributed Transaction Coordinator) system service.
For LINQ i am using TransactionScope to handle transactions. When i execute the queries i get an exception.
Underlying connection failed to Open.
and the inner exception is saying something about DTC. I read online that i will have to enable some service on the server. But i donot want to do that. How can i use transcactions without enabling DTC. My code is something like this
public void function1()
{
using(TransactionScope t = new TransactionScope())
{
RunSomeSelectQueries();
RunSomeInsertQueries();
RunSomeUpdate Queries();
t.Complete();
}
}
Thanks in advance.
You have a serious problem in you tx handling that will push al ot of load into various levels.
TransactioNScope is nice, but
Calling methods that open separate connections WITHOUT NEED is bad.
Here is why:
If a Tx has one connection, it is handled in the kernel as local transaciton scope.
If you have multiple connections (transacted ressources) you need DTC.
And:
DTC is much slower than just a connection, with a lot more load on the server (multiple open connections - they have to stay open until the transaction commits). Also that turns into a multi step commit - generally a lot of overhead and making things slower.
That generally is a "hey, I just use transactions" antipattern.
Properly you should make sure you only create one database connection UNLESS YOU NEED MORE THAN ONE (like multiple databases are involved) so that the transaction scope does not proppagate to the DTC for having multiple ressources.
Obviously you also should configure DTC correctly IF you need it, but again: in this case the real problem is that you abuse the transaction scope forcing a DTC propagation where none is actually needed.
Is it possible to retrieve the current SQL Transaction in c# when connection was closed?
sqlTransaction.Save("savePoint");
sqlConnection.Close() // im purposely closing it to test
if (sqlConnection.State == ConnectionState.Close)
{
sqlConnection.Open():
// is it possible to resume the sql transaction when I re-open
// the sql connection? how?
}
SqlTransaction.Save does not 'save' the transaction, instead it creates a transaction savepoint, which is something completely different:
Creates a savepoint in the transaction
that can be used to roll back a part
of the transaction, and specifies the
savepoint name.
A savepoint can be used before the transaction is committed to partially rollback some of the work done by the transaction. A typical example would be an attempt to do an update that may fail, so you create a savepoint before doing the update and in case of failure you rollback to the savepoint, thus preserving all the work done prior to the savepoint.
See Exception handling and nested transactions for an example of how to use savepoints.
Now back to your question, is there a way for a connection to start a connection, close, and when re-open, pick up the same transaction? Technically there is, by using the (now deprecated) sp_getbindtoken and sp_bindsession. But this is just a curiosity, there is absolutely no valid scenario for you to attempt to 'reuse' a transaction across two different sessions (two re-opens of a connection).
No, SQL Server will rollback any uncommitted transactions when the connection is terminated.
This seems to be a misunderstanding of a database transaction. Transactions are all-or-nothing conversations with the database. If you close the line of communication with the database by closing the connection, the conversation is over and the changes are not committed (the "nothing" part of "all-or-nothing").
No, I don't think you can do this.
I'm researching SqlClient's SqlBulkCopy in ADO.Net and have the following questions.
What will happen, if there was a network error during a SqlBulkCopy operation, running under as part of a transaction over a huge number of records?
Will the transaction be left open (neither committed, nor rolled back) in the server, until we manually kill it?
What is the best approach for sending a large number of records in two DataTables (InvoiceHeader, InvoiceDetails) in a DataSet to respective SQL Server tables(InvoiceHeader, InvoiceDetails)?
Thank you.
EDIT:
A few details I wanted to add, but forgot:
This is for .Net v3.5; I'm using Enterprise Library for all database interactions.
Assuming you are using a TransactionScope, my understanding is that no, the transaction will not be left open, because SQL Server will detect the ambient transaction and auto enlist. This means that the worst case is that the transaction times out, rolling back. You can change the transaction binding to specify what to do in the event of a timeout (you probably want explicit unbind).
EDIT: I am only accessing 1 database but a DTC transaction IS being created. I can see it in the DTC Transaction List GUI (Component services plugin). Why is this?
I need to perform a transaction (several insert commands) against 1 database.
Should I be using TransactionScope or IDbTransaction (connection.BeginTransaction)?
TransactionScope seems to be newer … but should it just be used for 2-phase commits?
Thanks
TransactionScope will only escalate to a distributed transaction if it detects more than one connection. This means that TransactionScope is just as lightweight as BeginTransaction for local transactions and TransactionScope is a lot easier to use.
As long as you use a single connection and do not close and re-open during a TransactionScope, it should not promote to a distributed transaction. If you do not have the DTC service running on your machine it will throw an exception if it tries to promote. If the DTC running, you will be non the wiser of the promotion except for a slight pause.
In the vast majority of cases, TransactionScope is much nicer to use, especially in conjunction with "using" blocks.
Be careful though, if you use SQL Server 2000. It does not play well with TransactionScope and will always escalate to a distributed transaction.
See this link for some details.