Migration for linq To sql with updateCheck
We will migrate a application that use linq to sql updatecheck = WhenChanged for concurrency for all column except some always. See https://learn.microsoft.com/fr-fr/dotnet/api/system.data.linq.mapping.columnattribute.updatecheck?view=netframework-4.8.1 I do not seen any solution to do this in EF core (except always => ConcurrencyCheck).
Example a record with with fields : Id, A, B Each user 1/ 2/ get the record, 1/ update the field A, and save, 2/ update the field B (A is not touched), it can save too without conflict. But if 2/ change A too => it detects a conflict.
My only idea for now, it is to mark all field with concurrencycheck, if there is an conflict, check field that other user has changed and change the current/original value and resave but i think it is some "barbare" way. ((if changed too by user => show user conflict to accept or to cancel))
Note for triage: looks like L2S has a special concurrency check: "WhenChanged: Use this column only when the member has been changed by the application."
I find a "bad" workaround
using Microsoft.EntityFrameworkCore.SqlServer.Update.Internal;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Update;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal;
#pragma warning disable EF1001 // Internal EF Core API usage.
namespace Test
{
public class InlSqlServerModificationCommandBatchFactory : IModificationCommandBatchFactory
{
private const int DefaultMaxBatchSize = 42;
private const int MaxMaxBatchSize = 1000;
private readonly int _maxBatchSize;
public InlSqlServerModificationCommandBatchFactory(
ModificationCommandBatchFactoryDependencies dependencies,
IDbContextOptions options)
{
Dependencies = dependencies;
_maxBatchSize = Math.Min(
options.Extensions.OfType<SqlServerOptionsExtension>().FirstOrDefault()?.MaxBatchSize ?? DefaultMaxBatchSize,
MaxMaxBatchSize);
if (_maxBatchSize <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(RelationalOptionsExtension.MaxBatchSize), RelationalStrings.InvalidMaxBatchSize(_maxBatchSize));
}
}
/// <summary>
/// Relational provider-specific dependencies for this service.
/// </summary>
protected virtual ModificationCommandBatchFactoryDependencies Dependencies { get; }
public virtual ModificationCommandBatch Create()
{
return new InlSqlServerModificationCommandBatch(Dependencies, _maxBatchSize);
}
}
public class InlSqlServerModificationCommandBatch : SqlServerModificationCommandBatch
{
public InlSqlServerModificationCommandBatch(ModificationCommandBatchFactoryDependencies dependencies,
int maxBatchSize) : base(dependencies, maxBatchSize)
{
}
protected override void AddCommand(IReadOnlyModificationCommand modificationCommand)
{
if (modificationCommand.EntityState == EntityState.Modified)
{
foreach (var columnModification in modificationCommand.ColumnModifications)
{
if (columnModification.IsWrite)
{
columnModification.IsCondition = true;
}
}
}
base.AddCommand(modificationCommand);
}
}
}
and i use in options
.ReplaceService<IModificationCommandBatchFactory, InlSqlServerModificationCommandBatchFactory>()