Open GoogleCodeExporter opened 9 years ago
In the actual [ValidateOrCreateTransaction(bool createTransaction)]
operation...
There is likely a simple fix if the change we made is not the right thing to
do...
Given this orignial code...
public static TransactionManager ValidateOrCreateTransaction(bool
createTransaction)
{
TransactionManager transactionManager =
Current.TransactionManager;
bool isBorrowedTransaction = (transactionManager != null &&
transactionManager.IsOpen);
NetTiersProvider dataProvider = Current.DataProvider;
if (isBorrowedTransaction && !
dataProvider.IsTransactionSupported)
{
if (transactionManager != null)
throw new Exception("Transaction Support is
not included with the current DataRepository provider. If using a provider
that
doesn't support transactions, such as a webservice, you should turn off
transaction
management.");
}
else if (isBorrowedTransaction &&
dataProvider.IsTransactionSupported)
{
if (transactionManager == null || !
transactionManager.IsOpen )
throw new ArgumentException("The
transactionManager is in an invalid state for this method. \nYou must begin
the
tranasction prior to using this method.");
}
else if (createTransaction && !isBorrowedTransaction &&
dataProvider.IsTransactionSupported)
{
transactionManager = CreateTransaction();
}
else if ( !createTransaction && !isBorrowedTransaction )
{
// if current transaction is not valid, but we don't
require one, return null
transactionManager = null;
}
return transactionManager;
You could in theory change the following line to look at
TransactionScope.Current to
be not null and infer that it is a "borrowed transaction"...
bool isBorrowedTransaction = (transactionManager != null &&
transactionManager.IsOpen) || (TransactionScope.Current != null);
Or something of that nature...
Original comment by bh...@yahoo.com
on 27 Apr 2010 at 9:20
On further review - this whole block needs evaluated to take the
TransactionScope
into consideration ( i.e. I didn't notice the "check" to ensure the
TransactionManager was open - same would apply to TransactionScope ).
Does the NetTiers "transaction manager" even serve a real role now that we have
the
TransactionScope? Should it be deprecated in favor of using TransactionScope?
Original comment by bh...@yahoo.com
on 27 Apr 2010 at 9:22
Just following up since I've seen activity from the team on other issues...
Please eyeball this one.. it's a true bug that can cause some serious headaches
as well as significant performance degregation (enlisting a distributed
transaction)...
Original comment by bh...@questis.com
on 21 Sep 2010 at 5:52
Hello,
Jeff, have you come across this issue before? I haven't seen this one in the
forums.
Thanks
-Blake Niemyjski
Original comment by bniemyjski
on 21 Sep 2010 at 8:33
We discovered it because code we had used previously was in an environment
where we had 60+ databases plus a centralized one... so obviously MSDTC was in
place and configured correclty....
On a following project we were challenged to deploy the app to the cloud with
Azure... They found Azure had no MSDTC support so to test if we could move to
SQL Azure or not, we disabled MSDTC on our local machines.... During testing
we found a specific scenario where it was trying to escalate to a distributed
transaction and failing (as would be expected with MSDTC disabled)...
After digging into the offending code, it was found that the code causing
escalation was the Delete method on the Service layer... and when we compared
it to other Delete operations that were NOT causing the escalation - we found
the different to be that in the one causing escalation we were passing the
integer Primar Key where the other NOT causing escalation was being passed the
Entity itself...
Once we stepped into the NetTiers code we found what was reported above...
Original comment by bh...@questis.com
on 21 Sep 2010 at 9:07
It seems the 'fix' here would be to simply pass in the 'noTranByDefault' value
as the other operations do... I'm not sure which template file this would occur
in...
Therfore our hack to the [ValidateOrCreateTransaction] operation to change the
hard-coded 'true' to 'false' (which on 2nd thought wasn't the 'right' fix but
it let us make 1 strategic centralized change to the templates with a lower
risk/turn-around time since we aren't that familiar with the templates) - is
un-needed and should not happen...
Additionally - I'm not sure what sets the actual value of 'noTranByDefault'
since it seems to be a constant or something set by perhaps the properties
file...
Original comment by bh...@questis.com
on 21 Sep 2010 at 9:34
I think I see it... In ComponentDataAcces.cst --- compare the Delete by PK
below with the others... for the "transactionManager =
ConnectionScope.ValidateOrCreateTransaction();" statement... almost all others
call it with the 'noTranByDefault' argument... On searching I see DeepSave
isn't doing it as well... (here at the client-site I've got the 2.3.0 Beta 1
templates on hand)...
/// <summary>
/// Deletes a row from the DataSource based on the PK'S <%= GetFunctionHeaderParameters(keys) %>
/// </summary>
<% foreach(string item in GetFunctionCallParameters(keys).Split(',')) { %>
/// <param name="<%= item.Trim() %>"><%=className%> pk id.</param>
<% } %>
<% if (RowVersion != null){ %>
/// <param name="<%=GetFieldName(RowVersion)%>">The timestamp field used for concurrency check.</param>
<% } %>
/// <remarks>Deletes based on primary key(s).</remarks>
/// <returns>Returns true if operation suceeded.</returns>
[DataObjectMethod(DataObjectMethodType.Delete)]
<%= constructorAccessModifierOnMembers %> bool <%=partialClassInternalPrefix%><%= MethodNames.Delete %>(<%= GetFunctionHeaderParameters(keys) %><% if(RowVersion != null) {Response.Write(", byte[] " + GetFieldName(RowVersion));}%>)
{
#region Security check
// throws security exception if not authorized
SecurityContext.IsAuthorized("<%= MethodNames.Delete %>");
#endregion Security check
#region Initialisation
bool result = false;
bool isBorrowedTransaction = false;
TransactionManager transactionManager = null;
NetTiersProvider dataProvider;
#endregion Initialisation
try
{
isBorrowedTransaction = ConnectionScope.Current.HasTransaction;
//since this is a read operation, don't create a tran by default, only use tran if provided to us for custom isolation level
transactionManager = ConnectionScope.ValidateOrCreateTransaction();
dataProvider = ConnectionScope.Current.DataProvider;
result = dataProvider.<%= GetClassName(SourceTable, ClassNameFormat.Provider) %>.<%= MethodNames.Delete %>(transactionManager, <%= GetFunctionCallParameters(keys) %><% if(RowVersion != null) {Response.Write(", " + GetFieldName(RowVersion));}%>);
if (!isBorrowedTransaction && transactionManager != null && transactionManager.IsOpen)
transactionManager.Commit();
}
catch (Exception exc)
{
#region Handle transaction rollback and exception
if (transactionManager != null && transactionManager.IsOpen)
transactionManager.Rollback();
//Handle exception based on policy
if (DomainUtil.HandleException(exc, layerExceptionPolicy))
throw;
#endregion Handle transaction rollback and exception
}
return result;
}
#endregion
<% } //endif(includedelete) %>
Original comment by bh...@questis.com
on 21 Sep 2010 at 9:40
Hello,
Thanks for updating this, it sure saves us a lot of time setting this up and
investigating!
Thanks
-Blake Niemyjski
Original comment by bniemyjski
on 21 Sep 2010 at 11:04
Original issue reported on code.google.com by
bh...@yahoo.com
on 27 Apr 2010 at 8:50