以下代码抛出TransactionAbortedException
消息“事务已中止”和内部TransactionPromotionException
,消息“尝试提升事务时失败”:
using ( TransactionScope transactionScope = new TransactionScope() )
{
try
{
using ( MyDataContext context = new MyDataContext() )
{
Guid accountID = new Guid( Request.QueryString[ "aid" ] );
Account account = ( from a in context.Accounts where a.UniqueID.Equals( accountID ) select a ).SingleOrDefault();
IQueryable < My_Data_Access_Layer.Login > loginList = from l in context.Logins where l.AccountID == account.AccountID select l;
foreach ( My_Data_Access_Layer.Login login in loginList )
{
MembershipUser membershipUser = Membership.GetUser( login.UniqueID );
}
[... lots of DeleteAllOnSubmit() calls]
context.SubmitChanges();
transactionScope.Complete();
}
}
catch ( Exception E )
{
[... reports the exception ...]
}
}
调用Membership.GetUser()
时出错。
我的连接字符串是:
<add name="MyConnectionString" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True"
providerName="System.Data.SqlClient" />
我read的所有内容都告诉我TransactionScope
应该神奇地应用于会员电话。用户存在(否则我希望返回null。)
答案 0 :(得分:6)
TransactionScope
类会屏蔽异常。最有可能发生的事情是该范围内的某些内容失败(抛出异常),而TransactionAbortedException
只是当控制退出using
块时发生的副作用。
尝试将TransactionScope
中的所有内容包装在try-catch
块中,并在catch
内进行重新抛出,并在那里设置断点;你应该能够看到真正的错误。
另一件事,TransactionScope.Complete
应该是在包含using
的{{1}}块结束之前执行的最后一个语句。在这种情况下,你可能应该没问题,因为之后你实际上并没有做任何工作,但是在内部范围内调用TransactionScope
往往会导致更容易出错的代码。
<强>更新强>
既然我们知道内部异常是什么(失败促进交易),那么更清楚的是发生了什么。
问题是在Complete
内,您实际上是在打开与TransactionScope
的另一个数据库连接。会员提供商不知道如何重新使用您已经开放的GetUser
;它必须打开自己的连接,当DataContext
看到它时,它会尝试升级到分布式事务。
它失败了,因为您可能在Web服务器,数据库服务器或两者上都禁用了MSDTC。
如果您打算打开两个单独的连接,则无法避免分布式事务,因此有很多方法可以解决此问题:
将TransactionScope
来电移至 GetUser
。也就是说,首先从会员提供者“读取”用户到列表中,然后在实际需要开始修改时启动事务。
完全删除TransactionScope
个来电并直接从数据库,同一个GetUser
或至少相同的连接上读取用户信息。
在参与交易的所有服务器上启用DTC(当交易促销时,性能将受到影响)。
我认为选项#1在这种情况下将是最好的;您需要从会员提供商处读取的数据在您阅读它和开始交易的时间之间进行更改是不太可能的。
答案 1 :(得分:1)
在一个层面上,它是正确的;事务总是中止(你没有调用Complete())。这是确切的代码吗?
此外,让DataContext
在之外的TransactionScope
让我怀疑它可能会做一些奇怪的事情,因为当数据上下文第一时事务不存在得到了。你试过(两个):
TransactionScope
跨越DataContext
Complete
using ( TransactionScope transactionScope = new TransactionScope() )
using ( MyDataContext context = new MyDataContext() )
{
/* ... */
transactionScope.Complete();
}