EF 中的事务性 SaveChangesAsync

MrS*_*Scf 4 c# entity-framework

Person我想以事务方式保存对数据库中实体列表的更改。我已经实现了该函数,但我不知道是否必须将其包装await Task.WhenAll(tasks);在 TransactionScope 中,或者它已经是我的代码足以获取它。

    public class MyService {

        public MyContext Context { get; }

        public MyService(
            IDatabaseInitializer<MyContext> initializer
        ) {
            Context = new MyContext(initializer);
        }

        public async Task<int> AddOrUpdateDataAsync(IEnumerable<Person> persons)
        {
            List<Task> tasks = new List<Task>();
            try
            {
                foreach (Person person in persons)
                {
                    person.Status = Status.Finish;
                    person.Changed = DateTime.Now;
                    person.Role = Role.Worker;
                    MyContext.Persons.AddOrUpdate(person);
                    tasks.Add(await MyContext.SaveChangesAsync(););
                }

                await Task.WhenAll(tasks);
                return 1;
            }
            catch (EntityCommandExecutionException ex)
            {
                return 0;
            }
        }

    }
Run Code Online (Sandbox Code Playgroud)

Der*_*ğlu 6

除非您完全确定自己在做什么,否则我不建议您通过返回 0 来处理异常。我总是更喜欢在最外层堆栈处处理异常并记录异常,然后采取适当的操作。如果可能的话,我建议您使用错误处理中间件(这根据您使用的框架、使用的方法以及情况而有所不同)。

另一方面,您不需要一个一个地更新每个对象。SaveChangesAsync全部操作完成后即可调用。

try
{
    foreach (Person person in persons)
    {
        person.Status = Status.Finish;
        person.Changed = DateTime.Now;
        person.Role = Role.Worker;
        MyContext.Persons.AddOrUpdate(person);
    }

    var affectedRows = await MyContext.SaveChangesAsync();
    return (int)(persons.Count == affectedRows);
}
catch (EntityCommandExecutionException ex)
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • SaveChangesAsync 是原子的吗?我想,我应该声明一个 TransactionScope。或者仅当我使用不同的 DataContext 时才需要 TransactionScope? (2认同)
  • 如果未手动设置,“SaveChangesAsync”应在后台创建一项事务。所以你的答案是肯定的。 (2认同)

Sha*_*ghi 5

其他答案都是正确的,但不解决您的问题是否SaveChangesAsync是原子的。
根据文档,对于EF6“EF Core”,您的问题的答案是“是”:

Ef 核心文档

默认情况下,如果数据库提供程序支持事务,则对 SaveChanges() 的单次调用中的所有更改都将应用到事务中。如果任何更改失败,则事务将回滚,并且任何更改都不会应用到数据库。这意味着 SaveChanges() 保证要么完全成功,要么在发生错误时保持数据库不变。

EF6 文档

在实体框架的所有版本中,每当您执行 SaveChanges() 在数据库上插入、更新或删除时,框架都会将该操作包装在事务中。此事务仅持续足够长的时间来执行操作,然后完成。当您执行另一个此类操作时,将启动一个新事务。