为了处理乐观并发,不能使用应用程序生成的DateTime属性,因为在多用户环境下,很可能在同一时刻有其他用户为同一属性生成相同的值。
如果你连接的是SQL Server,一个更安全的选择是在每个实体类中添加这样一个属性:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[ConcurrencyCheck]
public byte[] RowVersion { get; set; }
这正如微软在其文档中推荐的做法。你应该将保存操作包裹在一个"try...catch"块中,并且如果发生更新并发异常时重复该操作(比如使用"while"循环):
此外,在你的代码中,使用单一的DbContext来同时进行读取和写入操作会更加方便,这样一来,当读取时studentToBeModified会被附加到上下文中,随后你可以直接修改并保存它,过程更加简洁。Entity Framework的操作应当被视为一个工作单元,并且需要在短时间内完成。因此,只使用一个YourContext实例,实际上并不需要DbContext工厂。不过,我对你的代码做了一些调整:
public async Task<UpsertResponse> UpdateAsync(Student student)
{
using (var context = _dbContextFactory.CreateDbContext())
{
while (true)
{
try
{
var studentToBeModified = await context.Students.FirstOrDefaultAsync(x => x.Id == student.Id);
if (studentToBeModified != null)
{
studentToBeModified.Name = student.Name;
studentToBeModified.LastModified = DateTimeOffset.UtcNow; // 如果你需要保存更新时间
await context.SaveChangesAsync();
break;
}
}
catch (DbUpdateConcurrencyException ex)
{
context.ChangeTracker.Clear(); // 清除变更跟踪器,准备重新尝试
}
}
// 你的代码继续往下...
}
}