引摘:
1、EF对事务进行了封装:无论何时执行任何涉及Create,Update或Delete的查询,都会默认创建事务。当DbContext类上的SaveChanges()方法被调用时,事务就会提交,saveChange()是有事务性的
2. 依赖多个不同的Context的操作(即分布式操作)或者多次调用context.saveChanges()操作,会脱离EF事务封装,此时可使用TransactionScope实现事务操作
选择合适的事务管理 下面一一对号入座:
1、如果只有一个DbContext类,那么应该尽力使用EF的默认事务管理。我们总应该将所有的操作组成一个在相同的DbContext对象的作用域中执行的工作单元,SaveChanges()方法会处理提交事务。
2、如果使用了多个DbContext对象,那么管理事务的最佳方法可能就是把调用放到TransactionScope对象的作用域中了。
3、如果要执行原生SQL,并想把这些操作和事务关联起来,那么应该使用EF提供的Database.BeginTransaction()方法。然而这种方法只支持EF6,不支持之前的版本。
4、EF 6起,EF在DbContext对象上提供了Database.BeginTransaction()方法,当使用上下文类在事务中执行原生SQL命令时,这个方法特别有用。
1、控制器实现
/// <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(); }
2、存储过程
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方式
/// <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.BeginTransaction
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); }