【发布时间】:2021-03-19 16:32:10
【问题描述】:
我正在使用 SQL 服务器,并且我有一个表,其目的是保存树状结构:
create table TableName (
Id bigint identity,
Name nvarchar(50) null,
RootId bigint null,
ParentId bigint null,
Path nvarchar(100) null,
constraint PK_TableName primary key (Id)
)
“路径”列值由 INSTEAD OF INSERT、UPDATE 触发器生成。 我使用的是 EFCore 3.1,每次尝试向表中添加记录时,都会抛出 DbUpdateConcurrencyException。
我缺少什么 - 我该如何解决问题?
顺便说一句,当我禁用触发器插入通道时,当我发送常规 INSERT 命令时触发器工作。
感谢 Panagiotis 为您解答。我理解逻辑,但它仍然不起作用。我试过这个:
protected virtual void MapTableName(EntityTypeBuilder<TableName> config)
{
config.ToTable("TableName");
config.HasKey(t => t.Id);
config.Property(t => t.Id).ValueGeneratedOnAdd().IsConcurrencyToken();
config.Property(t => t.Name).IsConcurrencyToken().HasMaxLength(50);
config.Property(t => t.Description).IsConcurrencyToken().HasMaxLength(100);
config.Property(t => t.RootId).IsConcurrencyToken();
config.Property(t => t.ParentId).IsConcurrencyToken();
config.Property(t => t.Path).HasMaxLength(100).ValueGeneratedOnAddOrUpdate();
config.Property(t => t.TypeId).IsConcurrencyToken();
config.Property(t => t.IsActive).IsConcurrencyToken();
config.HasOne(t => t.LocationType).WithMany(t => t.TableNames).HasForeignKey(t => t.TypeId);
config.HasOne(t => t.ParentTableName).WithMany(t => t.ChilTableNames).HasForeignKey(t => t.ParentId);
config.HasOne(t => t.RootTableName).WithMany(t => t.ChildTableNamesAll).HasForeignKey(t => t.RootId);
}
但我得到了相同的答案:
"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. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions."
【问题讨论】:
-
因为 EF 认为您正在添加一条新记录,所以它期望在 @@IDENTITY 中看到一个值。但事实并非如此,因为您正在更新现有记录。
-
@CaptainKenpachi 这不是并发异常的意义
-
我能想到两件事:将触发器的逻辑移动到应用程序层,或者为 INSERT 命令生成 SQL,然后针对 context.database 执行它.
-
问题出在
Path。 EF Core 默认使用乐观并发,假设冲突(即另一个连接对同一记录的更改)很少见。为确保自加载记录后值未更改,EF Core 将检查rowversion列的值(如果存在),或将 all 原始属性值与表的值进行比较。如果Path在 EF 不知情的情况下更改,则会出现并发冲突 -
@PanagiotisKanavos 添加新记录时没有并发检查。问题显然是触发器弄乱了
insert into table values ...; select Id from table where @@ROWCOUNT = 1 AND [Id] = scope_identity()用于检索标识值的典型“自动增量”逻辑。因此,“预计会影响 1 行,但实际上影响了 0 行” 部分错误消息(其余部分只是误导)。
标签: sql sql-server entity-framework-core