我正在创建将在应用程序中使用的默认并发策略。

我决定采取乐观的策略。

我所有的实体都映射为Table per Type (TPT)(使用继承)。我很快了解到,在 Entity Framework 上使用具有继承性的RowVersion类型的列时会出现问题:

Product

Id INT IDENTITY PRIMARY KEY
RowVersion ROWVERSION

Car (inherits Product records)

Color TYNIINT NOT NULL,
AnotherProperty....   

如果我更新Car表的记录,那么Product表中的RowVersion列将不会更新。

我计划在datetime2 (7)中使用Product类型的列,并在继承该表的表的任何记录被修改后手动对其进行更新。

我想我正在重新发明轮子。

在Entity Framework中使用ROWVERSION时,还有另一种方法可以对Table per Type (TPT)使用乐观并发策略吗?

编辑

我的映射:
class Product
{
    int Id { get; set; }
    string Name { get; set; }
    byte[] RowVersion { get; set; }
}

class Car : Product
{
    int Color { get; set; }
}

CodeFirst 约定。

只有Product实体上的RowVersion属性具有自定义定义:
modelBuilder.Entity<Product>()
    .Property(t => t.RowVersion)
    .IsConcurrencyToken();

最佳答案

在EF6和EF-core中,使用Sql Server时,都必须使用此映射:

modelBuilder.Entity<Product>()
.Property(t => t.RowVersion)
.IsRowVersion(); // Not: IsConcurrencyToken

IsConcurrencyToken 确实将属性配置为并发 token ,但是(将其用于byte[]属性时)
  • 数据类型为varbinary(max)
  • 如果不初始化,则其值始终为null
  • 在更新记录时,其值不会自动增加。

  • 另一方面, IsRowVersion
  • 具有数据类型rowversion(在Sql Server中,或在较早版本中为timestamp),因此
  • 其值永远不会为空,而
  • 在更新记录时,其值始终自动增加。
  • ,它会自动将该属性配置为开放式并发 token 。

  • 现在,当您更新Car时,您将看到两个更新语句:

    DECLARE @p int
    UPDATE [dbo].[Product]
    SET @p = 0
    WHERE (([Id] = @0) AND ([Rowversion] = @1))
    SELECT [Rowversion]
    FROM [dbo].[Product]
    WHERE @@ROWCOUNT > 0 AND [Id] = @0
    
    UPDATE [dbo].[Car]
    SET ...
    

    第一条语句不会更新任何内容,但是会增加行版本,如果行版本在其间进行更改,它将引发并发异常。
    [System.ComponentModel.DataAnnotations.Schema.Timestamp]属性是等效于IsRowVersion()的数据注释:
    [Timestamp]
    public byte[] RowVersion { get; set; }
    

    10-06 09:10