4

MVC 项目首先使用 EF 5 代码和 .NET 4.5。

我正在寻找一种将 dbContext 和 SimpleMembershipProvider 包装在单个事务中的方法。我尝试使用 TransactionScope,但由于成员资格提供程序将打开另一个连接,我得到一个异常(服务器“服务器名”上的 MSDTC 不可用)。

所以我虽然可以使用 ObjectContext.Connection.BeginTransaction 来代替。成员资格提供者不会成为事务的一部分,但我们的想法是将它放在某个地方,如果它失败,则不会提交事务。

Book bk1 = default(Book);
Book bk2 = default(Book);

object obc = (IObjectContextAdapter)dbContext;

obc.ObjectContext.Connection.Open();
using (tx == obc.ObjectContext.Connection.BeginTransaction) {

    bk1 = new Book {
        Name = "Book 1 Name",
        Location = "USA"
    };
    dbContext.Books.Add(bk1);
    dbContext.SaveChanges();
    bk2 = new Book {
        Name = "Book 2 Name. Book one Id is: " + bk1.Id,
        Location = "USA"
    };
    dbContext.Books.Add(bk2);
    dbContext.SaveChanges();

    // this is not part of the transaction, 
    // however if it trhows an exception the transaction is aborted.
    // I'm assuming that if we got here, the commit won't fail...    
    // But is it really true?
    WebSecurity.CreateUserAndAccount("username", "123456");

    tx.Commit();
}

无论如何,基于上面的代码:

  • 如果 WebSecurity.CreateUserAndAccount 失败,那么整个事情都会失败,这是意料之中的。
  • 如果 SaveChanges 方法中的任何一个失败,那么整个事情都会再次失败,因为我们没有到达执行 CreateUserAndAccount 的地方。

这整件事让我想到一个问题:它安全吗?我的意思是:

在我们成功执行 DbContext.SaveChanges 后,“提交”方法是否有可能抛出异常(以某种方式失败)?如果发生这种情况,我们将得到一个孤儿用户,因为提供者不是交易的一部分。

我很感激对此的任何意见或建议。

快速说明:有这篇不错的文章解释了为什么我必须将 dbContext 强制转换为 IObjectContextadapter 而不是使用它自己的连接属性,但我再也找不到它了。

4

1 回答 1

2

是的,Commit当然可以扔。一个简单的例子是连接断开。当然,还有其他情况。

你有几个选择:

  • 如果连接是共享的,同一数据库上的事务将不会升级为分布式。因此,您可以为 EF 和您的连接使用一个WebSecurity连接。
  • 在服务器上启动分布式事务控制器并接受升级。不是世界上最糟糕的事情。
  • 不要使用事务,而是更改操作的顺序,以便稍后可以完成或撤消部分成功的操作。例如,检测和清理“孤儿”用户。
于 2012-09-07T17:20:19.713 回答