LINQ 中的更新查询包含 WHERE 子句中的所有列,而不仅仅是主键列

Update query in LINQ contains all columns in WHERE clause instead of just the primary key column

我正在使用 Linq 更新 table 中的单个列,下面采用虚构的 table。

MyTable(PKID、ColumnToUpdate、SomeRandomColumn)

var row = (from x in DataContext.MyTable
           where b.PKID == 5
           select x).FirstOrDefault();

row.ColumnToUpdate = 20;
DataContext.SubmitChanges();

这会将列更新为预期的结果,这并不奇怪。但是,当我检查生成的 SQL 命令时,它会这样做:

UPDATE [dbo].[MyTable ]
SET [ColumnToUpdate ] = @p2
WHERE ([PKID] = @p0) AND ([SomeRandomColumn] = @p1) 

这是在执行更新,但前提是所有列都与实体期望的值相匹配,而不是单独引用主键列。

如果数据库列被另一个进程更改,这在这个特定项目中是非常可行的;例如。在获取要操作的行、计算要将值设置到的更改以及作为一批行发出更新命令之间存在 window。在这种情况下查询会导致异常,导致部分更新,除非我陷阱,重新加载数据并重新发送个别查询。它也有一个缺点,即行信息可能非常大(例如,包含 HTML 标记),并且整个事情都会传递给 SQL 并在处理较大的批次时减慢系统速度.

有没有办法让 Linq/Entity 仅根据 Where 子句中的 PK 列发出更新命令?

我从未在生产项目中使用过 LINQ-to-SQL,而且我从来不知道它默认应用乐观并发1

这是默认行为:

  1. 如果 table 没有 Timestamp/Rowversion2所有 列都有“更新检查”在 DBML 中设置为“始终”(主键列和计算列除外,即所有可更新列)。
  2. 如果 table 确实有一个 Timestamp/Rowversion 列,则该列在 DBML 中将“时间戳”设置为“真”,并且所有列的“更新检查”=“从不”。

“更新检查”或“时间戳”将列标记为并发标记。这就是为什么在更新语句中您会在(不是这样)“随机”列上看到这些额外的谓词。显然,您模型中的 table 没有 Timestamp/Rowversion 列,因此更新会检查 table.

中所有可更新列的值

1 乐观并发:更新记录时不设置排他锁,更新时检查所有或选定列的现有值。如果其中一个列值在获取数据和保存数据之间被其他用户更改,则会发生更新异常。

2 数据类型 TimestampRowversion 的列在更新记录时自动递增,因此会检测对该记录的所有并发更改。