-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Feature: Optimistic Concurrency Support via Concurrency Tokens
Summary
Add support for optimistic concurrency control in DbConnectionPlus using concurrency token columns.
When an entity is updated or deleted, DbConnectionPlus should ensure the entity’s concurrency token(s) match the current value(s) in the database row. If it doesn’t, the operation must fail with a concurrency exception.
Motivation / Problem
DbConnectionPlus currently updates and deletes rows without verifying whether the row has been modified by another process since it was last read. This can lead to lost updates and silent overwrites.
By supporting concurrency tokens, DbConnectionPlus can detect conflicting updates and provide consistent optimistic concurrency behavior similar to EF Core.
Requirements
1) Concurrency token kinds
1.1 Native database-generated concurrency tokens (row version)
Such tokens are automatically generated and updated by the database system when a row is inserted or updated.
Example: SQL Server timestamp or rowversion column.
1.2 Application-managed concurrency tokens
Such tokens are managed by the application rather than by the database.
Example: A GUID column.
2) Configuration
2.1 Attribute-based configuration
Support marking a property as a row version concurrency token using System.ComponentModel.DataAnnotations.TimestampAttribute:
public class Product
{
[Timestamp]
public byte[] RowVersion { get; set; }
}Support marking a property as a concurrency token using System.ComponentModel.DataAnnotations.ConcurrencyCheckAttribute:
public class Product
{
[ConcurrencyCheck]
public byte[] ConcurrencyToken { get; set; }
}2.2 Fluent configuration
Support configuring concurrency tokens via fluent API:
DbConnectionExtensions.Configure(config =>
{
config.Entity<Product>()
.Property(p => p.RowVersion )
.IsRowVersion();
config.Entity<Product>()
.Property(p => p.ConcurrencyToken )
.IsConcurrencyToken();
});Acceptance criteria
- Concurrency token configuration must be reflected in entity metadata.
3) Update behavior
If an entity has one or more configured concurrency token properties:
- The
UPDATEmust only succeed if the concurrency token value(s) in the entity match the value(s) currently stored in the database. - If the values do not match, DbConnectionPlus must:
- not perform the update
- throw
DbUpdateConcurrencyException
Implementation requirement
- Concurrency token values must be included in the
WHEREclause of the generatedUPDATEstatement. - DbConnectionPlus must validate concurrency by checking the number of affected rows returned by the database.
- If
affectedRows == 0, treat it as a concurrency conflict and throwDbUpdateConcurrencyException.
- If
4) Delete behavior
If an entity has one or more configured concurrency token properties:
- The
DELETEmust only succeed if the concurrency token value(s) in the entity match the value(s) currently stored in the database. - If the values do not match, DbConnectionPlus must:
- not perform the delete
- throw
DbUpdateConcurrencyException
Implementation requirement
- Concurrency token values must be included in the
WHEREclause of the generatedDELETEstatement. - DbConnectionPlus must validate concurrency by checking the number of affected rows returned by the database.
- If
affectedRows == 0, throwDbUpdateConcurrencyException.
- If
5) Refresh row version concurrency tokens after update
After a successful update of an entity with row version concurrency token properties, DbConnectionPlus must:
- Retrieve the new row verion values generated by the database.
- Automatically update the entity instance’s row version properties with the fresh values returned.
- Ensure the entity reflects the current state of the database, preventing stale row version values in the in-memory entity.
Batch Operations
When updating or deleting multiple entities in a batch:
- DbConnectionPlus must stop processing the batch as soon as it detects a concurrency conflict.
- Updates/deletes that completed successfully before the failing entity should remain persisted.
- The operation must throw
DbUpdateConcurrencyExceptionfor the first entity that fails concurrency validation.
Testing
Add unit + integration tests across all supported database systems to verify:
Metadata / configuration
- Properties marked with
[ConcurrencyCheck]are correctly recognized as concurrency tokens. - Properties marked with
[Timestamp]are correctly recognized as row version concurrency tokens. - Fluent configuration via
.IsConcurrencyToken()is correctly applied. - Fluent configuration via
.IsRowVersion()is correctly applied.
Update/Delete behavior
- Updates include concurrency token values in the
WHEREclause. - Deletes include concurrency token values in the
WHEREclause. - Operations succeed when values match.
- Operations fail when values differ.
Row version concurrency token refresh
- After successful updates, row version concurrency token properties on the entity are updated with fresh values from the database.
Exception behavior
DbUpdateConcurrencyExceptionis thrown when concurrency checks fail.- Batch operations stop at the first conflict and preserve prior successful operations.