【问题标题】:IsConcurrencyToken(true) does not actually check concurrency tokensIsConcurrencyToken(true) 实际上并不检查并发令牌
【发布时间】:2019-11-07 08:40:01
【问题描述】:

我有一个这样配置的属性:

public byte[] Timestamp { get; set; }

然后在我的 DbContext 中,我像这样使用 Fluent API:

modelBuilder.Entity<MyClass>()
.Property(x => x.Timestamp)
.IsRowVersion()
.IsConcurrencyToken(true);

所以我很自然地继续编写了一个单元测试,以确保时间戳设置错误的实体不会被保存。我使用 Sqlite 和一些自定义 Sql 使 RowVersion 在单元测试中工作,但令我惊讶的是,我从未遇到过异常。然后,我在我们的应用程序中对其进行了测试,当在实体上设置了错误的时间戳时,我也没有收到异常。

var myInstance = await myDbContext.Instances
.Include(x => x...)
.Include(x => x...)
.SingleAsync(x => x.Id == id);

// set other values, add new entities to relationships, aso

myInstance.Timestamp = new byte[] { 1, 2, 3, 4 };

await myDbContext.SaveChangesAsync();

我显然在这里遗漏了一些东西。我认为配置IsRowVersion 足以强制EF Core 在UPDATE 中包含WHERE Timestamp = 子句,但似乎并非如此。如您所见,我也尝试调用IsConcurrencyToken(即使它的默认值为true,只是为了确定)但无济于事。

编辑:我现在已经通过在我的SingleAsync 调用中包含时间戳来“解决”它,但这仍然让我不确定它是否仍然可能不会出现并发异常,因为我的实体上设置了Timestamp保存时显然根本没有检查?

【问题讨论】:

  • 您应该删除.IsConcurrencyToken(true)。似乎它覆盖了IsRowVersion,而后者是what you need
  • @GertArnold 删除/添加它实际上什么也没做,因为它只会创建一个空迁移。似乎原因是 ef core github.com/aspnet/EntityFrameworkCore/issues/18505 的已知行为
  • 那么.IsRowVersion() 显然优先。您应该在数据库中有一个rowversion 字段。为了进行测试,您最好在保存更改之前在同一记录上运行原始 SQL 更新语句。这更接近现实。

标签: ef-core-3.0


【解决方案1】:

这是 EF 核心的已知行为,如下所述:

https://github.com/aspnet/EntityFrameworkCore/issues/18505

手动更改令牌的值被视为无操作,因为从数据库中查询的原始值正在用于并发检查。手动更改该值没有任何作用,因为它实际上被忽略了。

【讨论】:

    猜你喜欢
    • 2015-09-28
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 2015-10-26
    • 2021-07-31
    • 1970-01-01
    相关资源
    最近更新 更多