引摘:sql
一、EF對事務進行了封裝:不管什麼時候執行任何涉及Create,Update或Delete的查詢,都會默認建立事務。當DbContext類上的SaveChanges()方法被調用時,事務就會提交,saveChange()是有事務性的
2. 依賴多個不一樣的Context的操做(即分佈式操做)或者屢次調用context.saveChanges()操做,會脫離EF事務封裝,此時可以使用TransactionScope實現事務操做json
選擇合適的事務管理 下面一一對號入座:
一、若是隻有一個DbContext類,那麼應該盡力使用EF的默認事務管理。咱們總應該將全部的操做組成一個在相同的DbContext對象的做用域中執行的工做單元,SaveChanges()方法會處理提交事務。
二、若是使用了多個DbContext對象,那麼管理事務的最佳方法可能就是把調用放到TransactionScope對象的做用域中了。
三、若是要執行原生SQL,並想把這些操做和事務關聯起來,那麼應該使用EF提供的Database.BeginTransaction()方法。然而這種方法只支持EF6,不支持以前的版本。
四、EF 6起,EF在DbContext對象上提供了Database.BeginTransaction()方法,當使用上下文類在事務中執行原生SQL命令時,這個方法特別有用。異步
一、控制器實現async
/// <summary> /// 增刪改 調用存儲過程 返回json格式 /// </summary> /// <returns></returns> public async Task<ActionResult> AddORDelORUpdate() { string strUpdateTime =DateTime.Now.ToString(); SqlParameter[] Param = { //new SqlParameter("@UpdateTime", System.Data.SqlDbType.DateTime), new SqlParameter("@UpdateTime", System.Data.SqlDbType.VarChar), new SqlParameter("@rt_code", System.Data.SqlDbType.NVarChar, 20), new SqlParameter("@rt_msg", System.Data.SqlDbType.NVarChar, 200) //輸出必定要定義字符類型長度 以避免報錯 }; if (string.IsNullOrEmpty(strUpdateTime)) { Param[0].Value = DBNull.Value; } else { Param[0].Value = strUpdateTime; } Param[1].Direction = ParameterDirection.Output; Param[2].Direction = ParameterDirection.Output; int numdata = await _DbContext.ExecuteNonQueryAsync("SP_AddDelUpdate", Param); string rtcode = Param[1].Value.ToString(); string rtmessage = Param[2].Value.ToString(); return AsResult.Success(); }
二、存儲過程分佈式
create PROCEDURE [dbo].[SP_AddDelUpdate] ( @UpdateTime varchar(50), @rt_code varchar(20) output, @rt_msg nvarchar(200) output ) AS BEGIN ; begin transaction begin try --if(@UpdateTime!=null) BEGIN update TRA_BargainOrder_Test set UpdateTime=@UpdateTime ; INSERT INTO TRA_BargainOrder_Test( UserID, CityCode, UpdateTime, BargainOrderCode, CreateTime, OrderStatus ) VALUES ( 3, 'SZ', @UpdateTime, '2018888888888888', GETDATE() , 1 ); END; commit transaction set @rt_code= '0000'; set @rt_msg= '執行成功!'; return end try begin catch set @rt_code= '9999'; set @rt_msg= '失敗,請稍候再試!'; rollback transaction end catch END
/// <summary> /// 返回int類型 增刪改 調用存儲過程 /// </summary> /// <returns></returns> public async Task<int> Add_ORDelORUpdate() { string strUpdateTime = DateTime.Now.ToString(); SqlParameter[] Param = { //new SqlParameter("@UpdateTime", System.Data.SqlDbType.DateTime), new SqlParameter("@UpdateTime", System.Data.SqlDbType.VarChar), new SqlParameter("@rt_code", System.Data.SqlDbType.NVarChar, 20), new SqlParameter("@rt_msg", System.Data.SqlDbType.NVarChar, 200) //輸出必定要定義字符類型長度 以避免報錯 }; if (string.IsNullOrEmpty(strUpdateTime)) { Param[0].Value = DBNull.Value; } else { Param[0].Value = strUpdateTime; } Param[1].Direction = ParameterDirection.Output; Param[2].Direction = ParameterDirection.Output; int numdata = await _DbContext.ExecuteNonQueryAsync("SP_AddDelUpdate", Param); string rtcode = Param[1].Value.ToString(); string rtmessage = Param[2].Value.ToString(); return numdata; }
存儲方法函數
public async static Task<int> ExecuteNonQueryAsync(this DefaultDbContext db, string sql, SqlParameter[] sqlParams) { int numint=0; using (var cmd = db.Database.Connection.CreateCommand()) { try { await db.Database.Connection.OpenAsync(); cmd.CommandText = sql; cmd.CommandType = System.Data.CommandType.StoredProcedure; cmd.Parameters.AddRange(sqlParams); numint = await cmd.ExecuteNonQueryAsync(); cmd.Connection.Close(); } catch (Exception ex) { _Logger.Error("執行數據" + ex.Message); //throw new Exception("提交失敗." + ex.Message); } finally { cmd.Connection.Dispose(); } return numint; } }
/// <summary> /// 返回類型 增刪改 調用存儲過程 返回一個輸出參數值 /// </summary> /// <returns></returns> public async Task<object> Add_ORDel_OR_Update() { string strUpdateTime = DateTime.Now.ToString(); SqlParameter[] Param = { //new SqlParameter("@UpdateTime", System.Data.SqlDbType.DateTime), new SqlParameter("@UpdateTime", System.Data.SqlDbType.VarChar), new SqlParameter("@rt_code", System.Data.SqlDbType.NVarChar, 20), new SqlParameter("@rt_msg", System.Data.SqlDbType.NVarChar, 200) //輸出必定要定義字符類型長度 以避免報錯 }; if (string.IsNullOrEmpty(strUpdateTime)) { Param[0].Value = DBNull.Value; } else { Param[0].Value = strUpdateTime; } Param[1].Direction = ParameterDirection.Output; Param[2].Direction = ParameterDirection.Output; int numdata = await _DbContext.ExecuteNonQueryAsync("SP_AddDelUpdate", Param); string rtcode = Param[1].Value.ToString(); string rtmessage = Param[2].Value.ToString(); var oParam = Param[Param.Length - 1];//返回最後一個輸出參數 return oParam; }
增刪改操做使用事物處理 這個主要結合ado.net方式this
/// <summary> /// 異步執行帶有參數的存儲過程公共方法 增刪改操做以及返回帶有輸出的參數 結合ADO.NET的事物處理 /// 這種狀況,咱們不能使用Database.BeginTransaction方法,由於咱們須要將SqlConnection和SqlTransaction對象傳給該函數,並把該函數放到咱們的事務裏。須要首先建立一個SqlConnection,而後開始SqlTransaction /// </summary> /// <param name="db"></param> /// <param name="sql"></param> /// <param name="sqlParams"></param> /// <returns></returns> public async static Task<int> ExecuteNonQueryAsync(this DefaultDbContext db, string sql, SqlParameter[] sqlParams) { var connectionString = ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString; int numint = 0; using (var conn = new SqlConnection(connectionString)) { await conn.OpenAsync(); using (var dbContextTransaction = conn.BeginTransaction(System.Data.IsolationLevel.Snapshot)) { try { var cmd = new SqlCommand(); using ( cmd.Connection = conn) { cmd.Transaction = dbContextTransaction; cmd.CommandText = sql; cmd.CommandType = System.Data.CommandType.StoredProcedure; cmd.Parameters.AddRange(sqlParams); numint = await cmd.ExecuteNonQueryAsync(); //cmd.Connection.Close(); dbContextTransaction.Commit(); } // db.Database.UseTransaction(dbContextTransaction); //using (var dbcontext = // new DefaultDbContext(conn, contextOwnsConnection: false)) //{ // dbcontext.Database.UseTransaction(dbContextTransaction); // //dbcontext.SaveChanges(); //} //dbContextTransaction.Commit(); } catch (Exception ex) { dbContextTransaction.Rollback(); _Logger.Error("執行數據" + ex.Message); } finally { dbContextTransaction.Dispose(); } return numint; } } }
單個savechanges上下文實現事務 Database.BeginTransactionspa
public ActionResult Index() { var dbContextTransaction = _DbContext.Database.BeginTransaction(); try { TRA_BargainOrder_Test TRA = new TRA_BargainOrder_Test { BargainOrderCode = "201896666666666", CityCode = "OO", OrderStatus =8, PayStatus = 0, UpdateTime = DateTime.Now, CreateTime = DateTime.Now, UserID=2, }; _DbContext.TRA_BargainOrders.Add(TRA); } _DbContext.SaveChanges(); dbContextTransaction.Commit(); } catch(Exception ex) { dbContextTransaction.Rollback(); _Logger.Error("執行數據" + ex.Message); } finally { dbContextTransaction.Dispose(); } var data = _DbContext.TRA_BargainOrders.ToList(); return View(data); }