Reputation: 21
I´m working on a distributed transaction issue that occurs using NET Framework 4.5. If I try to execute the app on a machine (and Dev Server also) using Framework 4.0 the components work fine. The problem started when I installed the fwk4.5 on my machine and run It on. I only installed the framework, I never changed the source code neither changed target framework on assemblies.
I need to know why It is happening, if the behavior of Entity Framework and distributed transactions have been changed after fwk4.0.
I read a lot but I couldn´t figure It out yet. Any help would be very apreciated.
Best Regards, Diego
Here you can see a simple code sample where I could reproduce the error:
Note: Notice that if the ObjectContext connection is not opened manually before transaction It works fine.
public static bool DoTran_ObjectContext()
{
String strc = ConfigurationManager.ConnectionStrings["TestDB2Entities"].ConnectionString; //"metadata=res://*/TestDb2Model.csdl|res://*/TestDb2Model.ssdl|res://*/TestDb2Model.msl;provider=System.Data.SqlClient;provider connection string="data source=.\sqlexpress;initial catalog=TestDB2;integrated security=True;pooling=False;multipleactiveresultsets=True;application name=EntityFramework""
ObjectContext oc = new ObjectContext(strc);
//this line causes enlist error at the end of function/////
oc.Connection.Open();
///////////////////////////////////////////////
var t = (from s in oc.CreateObjectSet() where s.Id == 2 select s).FirstOrDefault();
t.Valor = "Cambiado_" + DateTime.Now;
using (TransactionScope scope2 = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
{
String cstr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; //"Data Source=.\\sqlexpress;Initial Catalog=TestDB2;Integrated Security=True";
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(cstr);
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "insert into Tabla1_Db2 values('" + DateTime.Now.ToString() + "')";
SqlTransaction tran = conn.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
cmd.Transaction = tran;
cmd.ExecuteNonQuery();
tran.Commit();
conn.Close();
oc.SaveChanges();
scope2.Complete();
}
//On this line the error is thrown
var t2 = (from s in oc.CreateObjectSet() where s.Id == 2 select s).FirstOrDefault();
return true;
}
Error:
"Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction."
Thanks!
Upvotes: 2
Views: 2665
Reputation: 2428
I think the problem is related to IsolationLevel being different in one of the scopes as stated here
When using nested TransactionScope objects, all nested scopes must be configured to use exactly the same isolation level if they want to join the ambient transaction. If a nested TransactionScope object tries to join the ambient transaction yet it specifies a different isolation level, an ArgumentException is thrown.
By default isolation level is Serializable, you're setting your Transaction to be ReadCommitted, if your caller runs a Serializable transaction you're involved in it.
Upvotes: 1