EF中的事务SaveChangesAsync

时间:2019-03-11 13:30:54

标签: 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;
            }
        }

    }

3 个答案:

答案 0 :(得分:2)

除非您完全确定自己在做什么,否则我建议您不要通过返回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;
}

答案 1 :(得分:1)

tasks.Add(await MyContext.SaveChangesAsync(););

应该没有等待时间

tasks.Add(MyContext.SaveChangesAsync());

您的代码开始工作。 (await表达式返回异步结果,不带await返回将在以后执行的任务) 但是如前所述,您不应该每次将实体添加到上下文中时都执行SaveChangesAsync(),因为它可能对所有添加的实体都执行一次。

答案 2 :(得分:0)

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

Ef Core docs

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

EF6 docs

在所有版本的Entity Framework中,每当执行SaveChanges()在数据库上插入,更新或删除时,该框架都会将该操作包装在事务中。此事务仅持续很长时间以执行操作,然后完成。当您执行另一个这样的操作时,将开始新的事务。