C# DbUpdateException-捕获所有异常时,复制密钥错误不会受到影响
我有以下方法C# DbUpdateException-捕获所有异常时,复制密钥错误不会受到影响,c#,mysql,entity-framework-core,C#,Mysql,Entity Framework Core,我有以下方法 public async Task Foo() { try { //Do stuff bool inserted = false; int tries=0; while (!inserted && tries<2) { try {
public async Task Foo()
{
try
{
//Do stuff
bool inserted = false;
int tries=0;
while (!inserted && tries<2)
{
try
{
inserted = await Bar();
}
catch (Exception ex)
{
//log ex and continue
}
finally
{
if(!inserted)
{
tries++;
}
}
}
}
catch (Exception ex)
{
//log ex and continue
}
}
公共异步任务Foo()
{
尝试
{
//做事
bool-inserted=false;
int=0;
而(!inserted&&try o.id)+1;
wait Context.Set().AddAsync(objectToBeAdded);
wait Context.saveChangesSync();
返回true;
}
捕获(例外情况除外){
返回false;
}
}
代码在多线程环境中运行,每分钟运行多次,因此始终有可能出现以下异常
Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时出错。有关详细信息,请参见内部异常。-->MySql.Data.MySqlClient.MySqlException:键“PRIMARY”的重复条目“XXXXX”-->MySql.Data.MySqlClient.MySqlException:键“PRIMARY”的重复条目“XXXXX”
不幸的是,这是一个很难重现的错误,我们的问题是它会使应用程序崩溃,而不是重试和继续
我们无法更改表以支持自动递增主键
编辑:根据请求的完整堆栈跟踪
-错误-执行DbCommand(8ms)[参数=[@p0='?'(DbType=Int64),@p1='?'(DbType=Boolean),…,@pN='?'(DbType=Decimal)],CommandType='Text',CommandTimeout='600']插入表(id
,col1
,…colN
)值(@p0,@p1,../pN);
-错误-保存对上下文类型“Entities”的更改时,数据库中发生异常。Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时出错。有关详细信息,请参见内部异常。-->MySql.Data.MySqlClient.MySqlException:键“PRIMARY”的重复条目“XXXXX”-->MySql.Data.MySqlClient.MySqlException:键“PRIMARY”的重复条目“XXXXXX”
在C:\…\MySqlConnector\src\MySqlConnector\Core\ServerSession.tryasyncontuation(Task1 Task)中的MySqlConnector.Core.ServerSession.tryasyncontuation处:第1248行
位于System.Threading.Tasks.ContinuationResultTaskFromResultTask
2.InnerInvoke()
位于System.Threading.ExecutionContext.RunInternal(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)
---来自引发异常的上一个位置的堆栈结束跟踪---
位于System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task和currentTaskSlot)
---来自引发异常的上一个位置的堆栈结束跟踪---
在C中的MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior IOBehavior)处:…..\MySqlConnector\src\MySqlConnector\Core\ResultSet.cs:第42行
---内部异常堆栈跟踪的结束---
在C:..\mysqlconnector\src\mysqlconnector\MySql.Data.MySqlDataReader.ActivateResultSet(ResultSet ResultSet)中的MySql.Data.MySqlClient.MySqlDataReader.cs:第80行
在C中的MySql.Data.MySqlClient.MySqlDataReader.ReadFirstResultSetAsync(IOBehavior IOBehavior)处:…..\mysqlconnector\src\mysqlconnector\MySql.Data.MySqlClient\MySqlDataReader.cs:第302行
在C中的MySql.Data.MySqlClient.MySqlDataReader.CreateAsync(MySqlCommand命令,CommandBehavior,ResultSetProtocol ResultSetProtocol,IOBehavior IOBehavior)处:…\mysqlconnector\src\mysqlconnector\MySql.Data.MySqlClient\MySqlDataReader.cs:第287行
在C中的MySqlConnector.Core.TextCommandExecutor.ExecuteReaderAsync(字符串commandText,MySqlParameterCollection参数Collection,CommandBehavior,IOBehavior,IOBehavior,CancellationToken CancellationToken)处:…..\MySqlConnector\src\MySqlConnector\Core\TextCommandExecutor.cs:第37行
在Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteAsync(IRelationalConnection连接,DbCommandMethod executeMethod,iRelationalDYDictionary2参数值,CancellationToken CancellationToken)
位于Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection连接,CancellationToken CancellationToken)
---内部异常堆栈跟踪的结束---
位于Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection连接,CancellationToken CancellationToken)
在Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext,ValueTuple
2参数,CancellationToken CancellationToken)
在Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4操作,Func
4验证成功,TState状态,CancellationToken CancellationToken)
在Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4操作,Func
4验证成功,TState状态,CancellationToken CancellationToken)
在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesSync(IReadOnlyList`1 EntriesToken保存,CancellationToken CancellationToken)
位于Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesSync(布尔接受ChangesOnSuccess,CancellationToken CancellationToken)
在Microsoft.EntityFrameworkCore.DbContext.SaveChangesSync(布尔值AcceptillChangesOnSuccess,CancellationToken CancellationToken)
就我所见,您没有从DbContext
中删除添加的对象,因此重复键仍然存在
你应该
要么
或者每次从头开始创建一个新的DbContext
,以确保安全
就我所见,您没有从DbContext
中删除添加的对象,因此重复键仍然存在
你应该
要么
或者每次从头开始创建一个新的DbContext
,以确保安全
我想,让这个错误难以重现的原因是,代码是异步运行的。
您通过在中查询当前最大id来获取新的最大id
public async Task<bool> Bar()
{
//setup opbject to be inserted to database
try
{
//the table can not have auto incrememnt so we read the max value
objectToBeAdded.id = Context.Set<object>().Max(o => o.id) + 1;
await Context.Set<object>().AddAsync(objectToBeAdded);
await Context.SaveChangesAsync();
return true;
}
catch (Exception ex) {
return false;
}
}
private object _lockObject = new object();
public async Task<bool> Bar()
{
//setup object to be inserted to database
try
{
// lock your changes, so they run in a safe order
lock (_lockObject)
{
//the table can not have auto incrememnt so we read the max value
objectToBeAdded.id = Context.Set<object>().Max(o => o.id) + 1;
await Context.Set<object>().AddAsync(objectToBeAdded);
await Context.SaveChangesAsync();
}
return true;
}
catch (Exception ex) {
return false;
}
}