EFCore乐观并发
在 Entity Framework Core 中,乐观并发是一种处理并发访问的方式,它允许多个用户同时访问和修改相同的数据,而不会发生冲突。乐观并发的实现通常涉及使用版本控制字段来检测数据更改,并在保存更改时检查这些字段是否与预期值匹配。
以下是在 Entity Framework Core 中实现乐观并发的一般步骤:
- 为实体模型添加一个用于乐观并发的版本属性。这通常是一个用于标识数据版本的属性,可以是整数、时间戳等。
public class Entity
{
public int Id { get; set; }
public string Name { get; set; }
[Timestamp]
public byte[] Version { get; set; } // 乐观并发的版本属性
}
- 在配置实体模型时,告诉 Entity Framework Core 使用版本属性进行乐观并发检查。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity>()
.Property(e => e.Version)
.IsConcurrencyToken(); // 告诉 EF 使用 Version 属性进行乐观并发检查
}
- 当更新实体时,Entity Framework Core 会自动检查版本属性,如果版本不匹配,则会抛出 DbUpdateConcurrencyException 异常,您可以在捕获该异常后进行处理。
try
{
// 查询要更新的实体
var entity = context.Entities.FirstOrDefault(e => e.Id == 1);
// 修改实体的其他属性
context.SaveChanges(); // 更新实体时进行乐观并发检查
}
catch (DbUpdateConcurrencyException ex)
{
// 处理并发异常,例如提示用户、日志记录等
}
通过使用乐观并发,Entity Framework Core 可以在并发访问和修改相同数据时提供一种有效的解决方案。
在处理并发冲突时,有时候我们可能希望采用未保存的值来解决冲突。在 Entity Framework Core 中,可以通过捕获 DbUpdateConcurrencyException 异常并采取适当的措施来实现这一点。
以下是在处理并发冲突时采用未保存的值的一般步骤:
try
{
// 查询要更新的实体
var entity = context.Entities.FirstOrDefault(e => e.Id == 1);
// 修改实体的其他属性
context.SaveChanges(); // 更新实体时进行并发检查
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var databaseValues = entry.GetDatabaseValues();
var originalValues = entry.OriginalValues;
// 使用未保存的值来解决并发冲突
foreach (var property in originalValues.Properties)
{
var databaseValue = databaseValues[property];
var originalValue = originalValues[property];
// 采用未保存的值来解决冲突
entry.CurrentValues[property] = originalValue;
}
// 重新尝试保存
context.SaveChanges();
}
在上述代码中,当捕获到 DbUpdateConcurrencyException 异常时,我们通过获取数据库中的当前值和原始值,然后使用未保存的值来解决冲突。我们遍历实体的所有属性,比较数据库值和原始值,然后将未保存的值重新应用到实体的当前值中。
通过采用未保存的值来处理并发冲突,我们可以确保在并发访问和修改相同数据时提供一种有效的解决方案,同时尽量减少冲突和数据丢失的可能性。
4.在代码中模拟并发
// 查询要更新的实体
var entity = context.Entities.FirstOrDefault(e => e.Id == 1);
entity.Name="test1";
//不需要savechange()就已经保存到数据库了
context.DataBase.ExecuteSqlInterpolated($"update Entities set Name='test2'");
context.SaveChanges();
上如代码模拟了两个并发,test2先保存到了数据库,test1执行完savechanes()后才把保存到数据库,应为test2保存到了数据库Version的版本时间戳跟新了,test1还是原来的时间戳,test1保存时和最新的时间戳比较,发现不一致,所以会进入修改并发异常。