如果我想完成这样的操作,我可能会使用下面的代码来直观地显示。
假设dbContext
和dbContext.Entries
分别是类型DbContext
(PostgreSQL(和DbSet<Entry>
。
var entry = await dbContext.Entries.FindAsync(key);
dbContext.Entries.Remove(entry);
await dbContext.SaveChangesAsync();
return entry;
然而,如果这段代码由两个或多个进程同时执行,我认为它可能不是完全孤立的(如果我错了,请纠正我(。例如,两个进程都先从第一行接收相同的条目,然后将其删除。尽管该条目仍将被正确删除,但两个进程均接收该条目,这违反了隔离规则。
我想知道是否可以使用EF Core来处理这种情况,从而使每个事务与其他事务完全隔离?
我从研究中发现的一种方法是用显式事务语句(docs(封装这段代码,并在需要时更改隔离级别。然而,从DbSet.FindAsync()
的文档中,如果";上下文正在跟踪给定的主键值">
我不确定DbSet.FindAsync()
操作是否会像修改操作(例如DbSet.Remove()
、DbSet.Add()
(一样,在明确声明的事务中按顺序考虑。
如果我的任何假设是错误的,请纠正我,并提前感谢!
编辑:很抱歉提及;我使用带有EF Core的PostgreSQL。
如果实体框架试图修改或删除丢失或最近更新的记录,它将抛出DbUpdateConcurrencyException
。
DbUpdateConcurrencyException
当预期实体的SaveChanges将导致数据库更新,但实际上数据库中没有行受到影响时,DbContext引发异常。这通常表示数据库已同时更新,因此预期匹配的并发令牌实际上与不匹配
因此,您可以将代码封装在try-catch中并捕获该异常。
try
{
var entry = await dbContext.Entries.FindAsync(key);
dbContext.Entries.Remove(entry);
await dbContext.SaveChangesAsync();
return entry;
}
catch(DbUpdateConcurrencyException e)
{
// do something with e
}
catch(Exception e)
{
// if something else happens, like null reference
}