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)
除非您完全确定自己在做什么,否则我不建议您通过返回 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是原子的。
根据文档,对于EF6“EF Core”,您的问题的答案是“是”:
默认情况下,如果数据库提供程序支持事务,则对 SaveChanges() 的单次调用中的所有更改都将应用到事务中。如果任何更改失败,则事务将回滚,并且任何更改都不会应用到数据库。这意味着 SaveChanges() 保证要么完全成功,要么在发生错误时保持数据库不变。
在实体框架的所有版本中,每当您执行 SaveChanges() 在数据库上插入、更新或删除时,框架都会将该操作包装在事务中。此事务仅持续足够长的时间来执行操作,然后完成。当您执行另一个此类操作时,将启动一个新事务。