SaveChanges()没有回滚尝试的事务

本文关键字:事务 SaveChanges | 更新日期: 2023-09-27 18:09:36

我有以下代码(EntityContext。当前是一个DbContext):

try {
    Setting s = new Setting
    {
        id = 1,
        user_id = 0
    };
    EntityContext.Current.Settings.Add(s);
    EntityContext.Current.SaveChanges(); //this violates a foreign key constraint and therefore throws an exception
} catch (Exception ex) {
    ErrorContext.Log(ex);
}

我所期望的(根据这个答案)是当挂起的更改失败时将回滚。然而,在我的错误记录方法中,我看到它们没有。

Error e = new Error
{
    message = ex.Message
};
EntityContext.Current.Errors.Add(e);
var pending = ((IObjectContextAdapter)EntityContext.Current).ObjectContext.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added);
//this contains both my new error entity and my old setting entity which shouldn't be here
EntityContext.Current.SaveChanges();

当我的应用程序试图在数据库中记录错误时,它还尝试(再次)保存带有无效外键约束的设置,这将导致错误日志记录的添加失败。

这是我第一次在EF中遇到这种行为。我尝试在事务中包装第一个SaveChanges(),但发生了同样的问题。

根据这个答案,我的连接字符串也不包含Enlist=false。我很茫然。这是预期行为吗?我怎样才能防止这种情况发生呢?

SaveChanges()没有回滚尝试的事务

这是预期的行为。SaveChanges尝试在单个数据库事务中提交所有更改。如果失败,则回滚数据库事务,并且不会向数据库写入任何内容。

但是失败的事务不会改变上下文中实体的状态。这就是为什么你的Setting实体仍然处于Added状态。

Error实体附加到相同的上下文中是一个问题,因为您通常无法将其存储到数据库中,就像本例中一样。我会考虑总是在一个新的上下文中使用专用方法编写错误日志,该方法只打开一个新的上下文中,将Error实体添加到该上下文中并保存更改。然后立即处理。