我们正在使用 ExecutionStrategy 并在我们的数据库上下文中有这个辅助方法:
public Task<T> ExecuteWithinTransactionAsync<T>(Func<IDbContextTransaction, Task<T>> operation, string operationInfo)
{
int counter = 0;
return Database.CreateExecutionStrategy().ExecuteAsync(RunOperationWithinTransaction);
async Task<T> RunOperationWithinTransaction()
{
counter++;
if (counter > 1)
{
Logger.Log(LogLevel.Warn, $"Executing ({counter}. time) transaction for {operationInfo}.");
ClearChangeTracker();
}
using (var transaction = await Database.BeginTransactionAsync(IsolationLevel.Serializable))
{
return await operation.Invoke(transaction);
}
}
}
我们在调用复杂/脆弱的业务逻辑时使用 ExecuteWithinTransactionAsync
,这些业务逻辑应该在可序列化事务中可靠地执行。我们正在使用 Postgres,因此我们的事务可能会由于序列化问题而中止。执行策略检测到它并重试操作。这很好用。但是 EF 仍然保留上次执行的旧缓存。这就是我们引入 ClearChangeTracker
的原因,它看起来像这样:
private void ClearChangeTracker()
{
ChangeTracker.DetectChanges();
foreach (var entity in ChangeTracker.Entries().ToList())
{
entity.State = EntityState.Detached;
}
}
这似乎工作正常,直到我们发现它不再工作的情况。当我们将新实体添加到导航属性列表时,这些实体不会在下次尝试时被删除。例如
var parent = context.Parents.FirstOrDefault(p => p.Id == 1);
if (parent.Children.Any())
{
throw new Exception("Parent already has a child"); // This exception is thrown on the second try
}
parent.Children.Add(new Child());
context.SaveChangesAsync();
因此,如果最后一行 context.SaveChangesAsync()
失败,并且整个操作重新运行,parent.Children
已经包含在 中添加的新子项>parent.Children.Add(new Child());
并且我没有找到任何方法从 EF 中删除该项目。
但是,如果我们删除检查 (if (parent.Children.Any())
),如果该项目已经存在或不存在,并且再次尝试添加它,它只会被存储在数据库中一次。
我试图弄清楚如何正确地清除 DbContext,但大多数时候,答案只是创建一个新的 DbContext。但是,这不是一个选项,因为 ExecutionStrategy 需要 DbContext。这就是为什么我想知道,使用 ExecutionStrategy 并在每次重试时都有一个干净的 DbContext 的建议方法是什么。
更多技术细节
- EF 核心版本:1.1.2
- 数据库提供者:Npgsql.EntityFrameworkCore.PostgreSQL (1.1.1)
- 操作系统:Windows 10,Linux 中的 Dockerized
最佳答案
在 ef-core 2.0.0 中,这个 new feature DbContext
引入了池化。为了使其正常工作,DbContext
实例现在能够重置其内部状态,因此它们可以作为"new"分发。可以像这样调用重置方法(在您的 DbContext
中):
((IDbContextPoolable)this).ResetState();
因此,如果您可以升级到 ef-core 2.0.0,那就去吧。不仅受益于这项新功能,它在许多方面也更加成熟。
免责声明:此方法仅供内部使用,因此 API 将来可能会发生变化。
关于c# - 如何正确使用 ExecutionStrategy?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46685823/