aspnetboilerplate/aspnetboilerplate · error · AbpDbConcurrencyException
ex.Message (wraps DbUpdateConcurrencyException)
Error message
ex.Message (wraps DbUpdateConcurrencyException)
What it means
When base.SaveChanges() raises DbUpdateConcurrencyException (an optimistic-concurrency conflict detected by EF Core), AbpDbContext catches it and rethrows as ABP's AbpDbConcurrencyException, carrying the original message and inner exception. This lets applications handle concurrency conflicts with a single ABP exception type.
Solutions
- Catch AbpDbConcurrencyException at the application/service layer and inform the user to reload and re-apply changes
- Reload the entity (repository refresh / re-query) and retry the change after a conflict
- Add a [Timestamp] RowVersion column to enforce optimistic concurrency consistently
- Use ABP's built-in concurrency handling in application services (AbpServiceBase handles it for AJAX responses)
Example fix
// before
_repository.Update(order); // throws AbpDbConcurrencyException to caller unhandled
// after
try
{
_repository.Update(order);
await CurrentUnitOfWork.SaveChangesAsync();
}
catch (AbpDbConcurrencyException)
{
// reload entity, notify user, re-apply changes
await _repository.ReloadAsync(order);
} Defensive patterns
Strategy: try-catch
Validate before calling
// detect likely conflict before save (optional re-check)
var entry = dbContext.Entry(entity);
var dbRowVersion = await dbContext.Set<TRowVersionHolder>()
.Where(x => x.Id == entity.Id)
.Select(x => (long?)x.RowVersion)
.FirstOrDefaultAsync();
if (dbRowVersion.HasValue && dbRowVersion != entry.Property("RowVersion").CurrentValue)
{
// conflict already exists; reload entity instead of saving
} Type guard
bool isConcurrencyConflict(Exception ex)
=> ex is AbpDbConcurrencyException || ex.InnerException is DbUpdateConcurrencyException; Try / catch
try
{
await CurrentUnitOfWork.SaveChangesAsync();
}
catch (AbpDbConcurrencyException ex)
{
Logger.Warn($"Concurrency conflict on entity: {ex.Message}");
await CurrentUnitOfWork.RollbackAsync();
throw new UserFriendlyException(L("ConcurrencyConflictMessage"));
} Prevention
- Add [Timestamp]/RowVersion columns to frequently updated entities
- Keep entity instances short-lived; reload before editing in long sessions
- Catch AbpDbConcurrencyException at the application service boundary and show a friendly message
- Implement reload-and-retry logic for background jobs
When it happens
Trigger: Calling SaveChanges() (or the surrounding repository/UoW save) on an AbpDbContext while another transaction modified the same row, so the UPDATE affects 0 rows and EF raises DbUpdateConcurrencyException.
Common situations: Two users editing the same entity concurrently; [Timestamp]/RowVersion concurrency tokens; stale entity loaded earlier and saved after a competing update; retry loops causing double writes.
Related errors
- Your EF Core database provider does not support…
- A dictionary can not contain same key twice. There are some…
- A dictionary can not contain same key twice. There are some…
- A Localization Xml must include localizationDictionary as…
- abp.ui.clearBusy is not implemented!
AI-assisted analysis of aspnetboilerplate/aspnetboilerplate@2323c13a15 (2026-09-08).
Data as JSON: /api/errors/3a0da6b960c66d7d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Abp.EntityFrameworkCore/EntityFrameworkCore/AbpDbContext.cs:276
.Entity<TEntity>()
.Property(property.Name)
.HasConversion(dateTimeValueConverter);
});
}
}
public override int SaveChanges()
{
try
{
var changeReport = ApplyAbpConcepts();
var result = base.SaveChanges();
EntityChangeEventHelper.TriggerEvents(changeReport);
return result;
}
catch (DbUpdateConcurrencyException ex)
{
throw new AbpDbConcurrencyException(ex.Message, ex);
}
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
try
{
var changeReport = ApplyAbpConcepts();
var result = await base.SaveChangesAsync(cancellationToken);
await EntityChangeEventHelper.TriggerEventsAsync(changeReport);
return result;
}
catch (DbUpdateConcurrencyException ex)
{
throw new AbpDbConcurrencyException(ex.Message, ex);
}
}
View on GitHub (pinned to 2323c13a15)