如何在实体框架 6 失败的事务中记录数据库中的错误

问题描述 投票:0回答:1

如果我正在事务中进行大量更新,并且它抛出异常,我仍然想在同一数据库上下文中的表中记录一些信息,以便我知道发生了什么。我错误地认为,根据这个答案,我所需要做的就是创建一个新的 context 实例,并且这些数据库插入将与事务分开。然而,它们也正在被回滚。我不确定是否是因为我缺少

new Database()
包装器,但它不允许我创建此语句,因为
Database
类似乎没有允许这样做的公共构造函数。
然后我看到了

这个答案

,这可能解释了原因。我可以看到您可能希望在事务中包含多个上下文。 那么我如何在事务中从该事务中排除一些数据库插入,这样它们就不会回滚?

这是一个过于简化的例子。实际上,

TransactionScope()

是在控制器的顶层创建的,并且

try{}
发生了许多深层方法调用。
var contextA = new ContextA();
using (var scope = new TransactionScope())
{
    // Log Errors in DB with new instance of same context
    var contextAforLogging = new ContextA()
    
    // Save entity in context A
    contextA.Save(...);
    
    //log step
    contextAforLogging.Save(...);
    contextAforLogging.SaveChanges();

    // More updates to original entity in context A
    contextA.Save(...);
    
    //log step
    contextAforLogging.Save(...);
    contextAforLogging.SaveChanges();
    
    // Commit tx-scope
    scope.Complete();          
}
catch (Exception ex) {
   return....;                        
}
     

	
sql-server entity-framework transactions entity-framework-6 transactionscope
1个回答
0
投票

using var transaction = context1.BeginTransaction(); context2.Database.UseTransaction(transaction.GetDbTransaction());

如果“否”,那么您很可能不需要显式交易。 EF 已经将操作包装在事务中,并利用导航属性将相关实体作为聚合根插入,将看到自动设置的 FK 等内容。当调用 
SaveChanges

时,任何完全独立的实体也将全部保存在事务范围内。

如果您确实需要 

TransactionScope

,那么您的日志记录代码可以选择退出事务范围。我建议使用 Log() 方法来封装它,这样就不会在某个地方遗漏它:

private void Log(string message)
{
    using var txScope = new TransactionScope(TransactionScopeOption.Suppress));
    using var contextForLogging = new AppDbContext(); // or better a DbContextFactory.Create()
//log step

    var logEntry = new LogEntry(message);
    contextForLogging.Logs.Add(logEntry);
    contextforLogging.SaveChanges();
    txScope.Commit();
}

理想情况下,当使用单个 DbContext 处理工作时,您应该避免多次调用 
SaveChanges()

。这通常表明您忽略了导航属性并尝试手动管理实体之间的关系,而 EF 完全在幕后支持这种关系。

    

© www.soinside.com 2019 - 2024. All rights reserved.