который я использую для параллелизма, а не

аюсь использовать оптимистическую проверку параллелизма в EF Core с SQLite. Самый простой позитивный сценарий (даже без самого параллелизма) дает мнеMicrosoft.EntityFrameworkCore.DbUpdateConcurrencyException: 'Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.

Сущность:

public class Blog
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public byte[] Timestamp { get; set; }
}

Контекст:

internal class Context : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite(@"Data Source=D:\incoming\test.db");
        ///optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasKey(p => p.Id);

        modelBuilder.Entity<Blog>()
            .Property(p => p.Timestamp)
            .IsRowVersion()
            .HasDefaultValueSql("CURRENT_TIMESTAMP");
    }
}

Образец:

internal class Program
{
    public static void Main(string[] args)
    {
        var id = Guid.NewGuid();
        using (var db = new Context())
        {
            db.Database.EnsureDeleted();
            db.Database.EnsureCreated();
            db.Blogs.Add(new Blog { Id = id, Name = "1" });
            db.SaveChanges();
        }

        using (var db = new Context())
        {
            var existing = db.Blogs.Find(id);
            existing.Name = "2";
            db.SaveChanges(); // Exception thrown: 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException'
        }

    }
}

Я подозреваю, что это как-то связано с типами данных между EF и SQLite. Ведение журнала дает мне следующий запрос на мое обновление:

Executing DbCommand [Parameters=[@p1='2bcc42f5-5fd9-4cd6-b0a0-d1b843022a4b' (DbType = String), @p0='2' (Size = 1), @p2='0x323031382D31302D30372030393A34393A3331' (Size = 19) (DbType = String)], CommandType='Text', CommandTimeout='30']
UPDATE "Blogs" SET "Name" = @p0
WHERE "Id" = @p1 AND "Timestamp" = @p2;

Но типы столбцов BLOB для Id и Timestamp (SQLite не предоставляет UUID и типы столбцов timestamp):

В то же время, если я использую SQL Server (используйте закомментированную строку подключения + удалить.HasDefaultValueSql("CURRENT_TIMESTAMP")), образец работает правильно и обновляет отметку времени в БД.

Используемые пакеты:

<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.4" />

Я неправильно настроил модель для проверки параллелизма? Это сводит меня с ума, что я не могу заставить его работать с этим самым простым сценарием.

ОБНОВИТЬ: как я наконец заставил это работать Здесь показана только идея, но, возможно, она кому-нибудь поможет:

public class Blog
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public long Version { get; set; }
}

internal class Context : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite(@"Data Source=D:\incoming\test.db");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasKey(p => p.Id);

        modelBuilder.Entity<Blog>()
            .Property(p => p.Version)
            .IsConcurrencyToken();
    }
}

internal class Program
{
    public static void Main(string[] args)
    {
        var id = Guid.NewGuid();
        long ver;
        using (var db = new Context())
        {
            db.Database.EnsureDeleted();
            db.Database.EnsureCreated();
            var res = db.Blogs.Add(new Blog { Id = id, Name = "xxx", Version = DateTime.Now.Ticks});
            db.SaveChanges();
        }

        using (var db = new Context())
        {
            var existing = db.Blogs.Find(id);
            existing.Name = "yyy";
            existing.Version = DateTime.Now.Ticks;
            db.SaveChanges(); // success
        }

        using (var db = new Context())
        {
            var existing = db.Blogs.Find(id);
            existing.Name = "zzz";
            existing.Version = DateTime.Now.Ticks;
            db.SaveChanges(); // success
        }

        var t1 = Task.Run(() =>
        {
            using (var db = new Context())
            {
                var existing = db.Blogs.Find(id);
                existing.Name = "yyy";
                existing.Version = DateTime.Now.Ticks;
                db.SaveChanges();
            }
        });

        var t2 = Task.Run(() =>
        {
            using (var db = new Context())
            {
                var existing = db.Blogs.Find(id);
                existing.Name = "zzz";
                existing.Version = DateTime.Now.Ticks;
                db.SaveChanges();
            }
        });

        Task.WaitAll(t1, t2); // one of the tasks throws DbUpdateConcurrencyException
    }
}

Ответы на вопрос(2)

Ваш ответ на вопрос