使用 EF 的 DbContext.ExecuteSqlCommand() 的事务期间出现异常
Posted
技术标签:
【中文标题】使用 EF 的 DbContext.ExecuteSqlCommand() 的事务期间出现异常【英文标题】:Exception during transactions using EF's DbContext.ExecuteSqlCommand() 【发布时间】:2014-09-02 12:07:48 【问题描述】:使用 try-catch 结构,我试图弄清楚如果在事务的任何点捕获到异常该怎么办。下面是一个代码示例:
try
DbContext.ExecuteSqlCommand("BEGIN TRANSACTION"); //Line 1
DBContext.ExecuteSqlCommand("Some Insertion/Deletion Goes Here"); //Line 2
DbContext.ExecuteSqlCommand("COMMIT"); //Line 3
catch(Exception)
如果在执行“第 1 行”时捕获了预期,则除了警告错误外,无需执行任何操作。如果它在执行第二行时被捕获,我不知道我是否需要尝试回滚已成功打开的事务,如果第三行出现问题,也会发生同样的情况。
我是否应该只发送回滚?还是在一个方法调用中将所有命令直接发送到银行?
在 try-catch 内部有一个循环执行许多事务,例如示例中的事务(我需要大量小事务而不是大事务,因此我可以正确重用 SQL 的“_log”文件并避免它增长不必要的)。
如果任何事务出错,我只需将它们全部删除并告知发生了什么,但我不能将其变成一个大事务而只使用回滚,否则它会使日志文件变大到 40GB。
【问题讨论】:
【参考方案1】:认为这会有所帮助:
using (var ctx = new MyDbContext())
// begin a transaction in EF – note: this returns a DbContextTransaction object
// and will open the underlying database connection if necessary
using (var dbCtxTxn = ctx.Database.BeginTransaction())
try
// use DbContext as normal - query, update, call SaveChanges() etc. E.g.:
ctx.Database.ExecuteSqlCommand(
@"UPDATE MyEntity SET Processed = ‘Done’ "
+ "WHERE LastUpdated < ‘2013-03-05T16:43:00’");
var myNewEntity = new MyEntity() Text = @"My New Entity" ;
ctx.MyEntities.Add(myNewEntity);
ctx.SaveChanges();
dbCtxTxn.Commit();
catch (Exception e)
dbCtxTxn.Rollback();
// if DbContextTransaction opened the connection then it will close it here
取自:https://entityframework.codeplex.com/wikipage?title=Improved%20Transaction%20Support
基本上,它的想法是您的事务成为 using 块的一部分,并且在其中您可以使用实际的 sql 进行 try/catch。如果在 try/catch 中有任何失败,它将被回滚
【讨论】:
值得注意的是,这仅适用于 EF 6。对于旧版本的 EF,您应该改用 TransactionScope(请参阅 ***.com/questions/22382892/…) 如果我没记错术语,这是一种事务范围,但是当我根本不需要使用实体时这有用吗?您将整个事务编写为单个查询“开始事务/n 插入内容/n 提交”的答案有什么区别? 从示例中可以看出,他不是在处理实体,而是在处理内联 sql。这样做的好处是它取消了您的问题 - 您不必担心捕获发生的方式/位置,无论如何它都会被回滚。 如果交易无法打开怎么办?会跳过 using 块吗?【参考方案2】:从 Entity Framework 6 开始,ExecuteSqlCommand
使用自己的事务进行包装,如下所述:http://msdn.microsoft.com/en-gb/data/dn456843.aspx
除非您明确需要将多个 sql 命令滚动到单个事务中,否则无需明确开始新的事务范围。
关于事务日志增长,假设您的目标是 Sql Server,那么将事务日志操作设置为 simple
将确保日志在检查点之间得到回收。
显然,如果在整个导入过程中未维护事务日志历史记录,则没有隐式机制可以在失败时回滚所有数据。为简单起见,如果我需要删除所有行以防出错,我可能会在表中添加一个“已创建”日期时间字段,并根据筛选器从表中删除到已创建字段。
【讨论】:
我说要“正确”使用它哈哈哈,我之所以这么说是因为当我尝试使用单个查询来完成任务时,日志文件会增长到接近 40Gb 6gb,所以我正在创建小批量,当前一个操作被提交时将重用日志文件,因此不会超出需要扩展日志文件。恢复模型已经设置为简单但这个巨大的查询让我发疯了。无论如何感谢您的回答=]以上是关于使用 EF 的 DbContext.ExecuteSqlCommand() 的事务期间出现异常的主要内容,如果未能解决你的问题,请参考以下文章