zoukankan      html  css  js  c++  java
  • EF Working with Transactions

    原文:https://msdn.microsoft.com/en-us/data/dn456843.aspx

    Prior to EF6 Entity Framework insisted on opening the database connection itself (it threw an exception if it was passed a connection that was already open). Since a transaction can only be started on an open connection, this meant that the only way a user could wrap several operations into one transaction was either to use a TransactionScope or use the ObjectContext.Connection property and start calling Open() and BeginTransaction() directly on the returned EntityConnection object. In addition, API calls which contacted the database would fail if you had started a transaction on the underlying database connection on your own.

    Note: The limitation of only accepting closed connections was removed in Entity Framework 6. For details, see Connection Management (EF6 Onwards).

    Starting with EF6 the framework now provides:

    1. Database.BeginTransaction() : An easier method for a user to start and complete transactions themselves within an existing DbContext – allowing several operations to be combined within the same transaction and hence either all committed or all rolled back as one. It also allows the user to more easily specify the isolation level for the transaction.
    2. Database.UseTransaction() : which allows the DbContext to use a transaction which was started outside of the Entity Framework.

    Combining several operations into one transaction within the same context

    Database.BeginTransaction() has two overrides – one which takes an explicit IsolationLevel and one which takes no arguments and uses the default IsolationLevel from the underlying database provider. Both overrides return a DbContextTransaction object which provides Commit() and Rollback() methods which perform commit and rollback on the underlying store transaction.

    The DbContextTransaction is meant to be disposed once it has been committed or rolled back. One easy way to accomplish this is the using(…) {…} syntax which will automatically call Dispose() when the using block completes:

    static void StartOwnTransactionWithinContext() 
            { 
                using (var context = new BloggingContext()) 
                { 
                    using (var dbContextTransaction = context.Database.BeginTransaction()) 
                    { 
                        try 
                        { 
                            context.Database.ExecuteSqlCommand( 
                                @"UPDATE Blogs SET Rating = 5" + 
                                    " WHERE Name LIKE '%Entity Framework%'" 
                                ); 
     
                            var query = context.Posts.Where(p => p.Blog.Rating >= 5); 
                            foreach (var post in query) 
                            { 
                                post.Title += "[Cool Blog]"; 
                            } 
     
                            context.SaveChanges(); 
     
                            dbContextTransaction.Commit(); 
                        } 
                        catch (Exception) 
                        { 
                            dbContextTransaction.Rollback(); 
                        } 
                    } 
                } 
            } 

    Note: Beginning a transaction requires that the underlying store connection is open. So calling Database.BeginTransaction() will open the connection  if it is not already opened. If DbContextTransaction opened the connection then it will close it when Dispose() is called.

    Sometimes you would like a transaction which is even broader in scope and which includes operations on the same database but outside of EF completely. To accomplish this you must open the connection and start the transaction yourself and then tell EF a) to use the already-opened database connection, and b) to use the existing transaction on that connection.

    To do this you must define and use a constructor on your context class which inherits from one of the DbContext constructors which take i) an existing connection parameter and ii) the contextOwnsConnection boolean.

    Note: The contextOwnsConnection flag must be set to false when called in this scenario. This is important as it informs Entity Framework that it should not close the connection when it is done with it (e.g. see line 4 below):

    using (var conn = new SqlConnection("...")) 

        conn.Open(); 
        using (var context = new BloggingContext(conn, contextOwnsConnection: false)) 
        { 
        } 
    }

    Furthermore, you must start the transaction yourself (including the IsolationLevel if you want to avoid the default setting) and let the Entity Framework know that there is an existing transaction already started on the connection (see line 33 below).

    Then you are free to execute database operations either directly on the SqlConnection itself, or on the DbContext. All such operations are executed within one transaction. You take responsibility for committing or rolling back the transaction and for calling Dispose() on it, as well as for closing and disposing the database connection. E.g.:

    static void UsingExternalTransaction() 
            { 
                using (var conn = new SqlConnection("...")) 
                { 
                   conn.Open(); 
     
                   using (var sqlTxn = conn.BeginTransaction(System.Data.IsolationLevel.Snapshot)) 
                   { 
                       try 
                       { 
                           var sqlCommand = new SqlCommand(); 
                           sqlCommand.Connection = conn; 
                           sqlCommand.Transaction = sqlTxn; 
                           sqlCommand.CommandText = 
                               @"UPDATE Blogs SET Rating = 5" + 
                                " WHERE Name LIKE '%Entity Framework%'"; 
                           sqlCommand.ExecuteNonQuery(); 
     
                           using (var context =  
                             new BloggingContext(conn, contextOwnsConnection: false)) 
                            { 
                                context.Database.UseTransaction(sqlTxn); 
     
                                var query =  context.Posts.Where(p => p.Blog.Rating >= 5); 
                                foreach (var post in query) 
                                { 
                                    post.Title += "[Cool Blog]"; 
                                } 
                               context.SaveChanges(); 
                            } 
     
                            sqlTxn.Commit(); 
                        } 
                        catch (Exception) 
                        { 
                            sqlTxn.Rollback(); 
                        } 
                    } 
                } 
            } 
  • 相关阅读:
    一个功能完善的资源管理器
    数据结构和算法
    Build Native Mobile Apps in HTML5: PhoneGap from Start to Finish
    HTML5安全:CORS(跨域资源共享)简介
    Start A mobile web app
    ASP.NET MVC4 常见问题集
    ASP.NET MVC4 ASP.NET Web API OAuth2 delegation with Windows Azure Access Control Service
    【转】HTTP access control (CORS)
    ASP.NET MVC4最新特性介绍 (待续)
    C#实现小写金额转换大写的方法
  • 原文地址:https://www.cnblogs.com/ly7454/p/4599149.html
Copyright © 2011-2022 走看看