将事务范围与实体框架一起使用

时间:2012-11-21 05:30:42

标签: entity-framework transactionscope

我有两张桌子。第一个表包含一些数据。第二个表包含数据更改的历史记录。第一个表还包含引用上一个历史记录行的列。当第一个表中的行数据被更改时,复制将插入第二个表中,并在第一个列中更新引用最后一个数据副本的列。为此,我使用此代码

using (TransactionScope trn = new TransactionScope())
{
  Table1 t1=model.Table1.Where(t=>t==id).FirstOrDefault();
  /*update Table1 data*/
  Table2 t2=new Table2();
  t2.Table1=t1;
  model.AddToTable2(t2);
  /*set Table2 fields*/
  model.SaveChanges();

  t1.ref=t2.id;
  model.SaveChanges();
  trn.Complete();
}

使用TransactionScope保存符合数据是否严格?或者我需要使用其他方法?

2 个答案:

答案 0 :(得分:1)

您需要保存两次更改吗?如果表是相关的,您应该能够设置导航属性并仅保存所有更改一次。在这种情况下,您不需要自己创建一个事务 - EF会为您创建一个事务。如果您需要保存两次更改,则TransactionScope应该可以解决问题。打开时,该连接将登记到事务中。在代码片段中,您不会显示您的上下文是如何实例化的,以及连接在进入事务之前会发生什么,因此很难判断它是否正确。

答案 1 :(得分:-1)

Context类默认支持事务。但是对于每个新的上下文类实例,都会创建一个新的事务。这个新事务是一个嵌套事务,一旦调用相关上下文类的SaveChanges(),它就会被提交。

在这种情况下,我们甚至不需要TransactionScope。我们可以简单地检查两个操作的结果,如果它们成功,我们只需要调用SaveChanges()方法。

当我们将ADO.NET调用与Entity框架混合时,通常需要TransactionScope。在这种情况下使用TransactionScope的技巧是让上下文类知道您想要将它与您自己的事务一起使用。由于事务与作用域中的连接对象相关联,因此我们需要将上下文类与与事务作用域关联的连接一起使用。此外,我们需要让上下文类知道它不能拥有连接,因为它是由调用代码拥有的。所以我们可以这样做:

using (var scope = new TransactionScope(TransactionScopeOption.Required)) 
{ 
    using (var conn = new SqlConnection("...")) 
    { 
        conn.Open(); 

        var sqlCommand = new SqlCommand(); 
        sqlCommand.Connection = conn; 
        sqlCommand.CommandText = 
            @"UPDATE Blogs SET Rating = 5" + 
                " WHERE Name LIKE '%Entity Framework%'"; 
        sqlCommand.ExecuteNonQuery(); 

        using (var context = 
            new BloggingContext(conn, contextOwnsConnection: false)) 
        { 
            var query = context.Posts.Where(p => p.Blog.Rating > 5); 
            foreach (var post in query) 
            { 
                post.Title += "[Cool Blog]"; 
            } 
            context.SaveChanges(); 
        } 
    } 

    scope.Complete(); 
} 

请参阅:http://msdn.microsoft.com/en-us/data/dn456843.aspx