我找到了一种无需任何 3rd 方包
的简单方法
:通过添加一个通用扩展方法SetValue
,您可以简单地编写:
例子:
void Main()
{
var dc = this; // context
var p = dc.Purchases.Where(x=>x.Description.ToLower()=="bike")
.SetValue(w => w.Description = "Bicycle");
p.Dump();
dc.SubmitChanges();
}
如您所见,任何符合Where
条件的值都可以显式设置为新值,因此这里Bike
将替换为Bicycle
. 之后您可以查询该表以查看真正持久的更改。
当然Where
,如果您想更改所有记录,您也可以省略该语句,例如:
dc.Records.SetValue(x => x.Quantity = 100);
dc.SubmitChanges();
实体框架 (EF) / LINQ 跟踪这些更改,当您调用 .SubmitChanges() 时 - 如果您使用的是 LinqPad,您可以在 SQL 选项卡中看到 - 它将创建 SQL 代码,如下所示:
-- Region Parameters
DECLARE @p0 Int = 3
DECLARE @p1 VarChar(1000) = 'Bicycle'
-- EndRegion
UPDATE [Purchase]
SET [Description] = @p1
WHERE [ID] = @p0
对于小的更改,这是可以的,但对于大型表,它变得低效,因为它使用 ID 列来识别和更改记录,而不是 .SetValue 定义的 Description 列。
理论上 EF 可以对此进行优化,但正如您所见,它并没有这样做。因此,如果您想要真正的批量操作,您需要改为运行 SQL 命令或创建您通过 EF 调用的存储过程(用于复杂查询)。
扩展方法SetValue
这种扩展方法可以解决问题(不需要其他 3rd 方包):
// see: https://visualstudiomagazine.com/articles/2019/07/01/updating-linq.aspx
public static class Extensions
{
public static IEnumerable<T> SetValue<T>(this IEnumerable<T> items,
Action<T> updateMethod)
{
foreach (T item in items)
{
updateMethod(item);
}
return items;
}
}
注意:
上面的示例使用Nutshell示例数据库,您可以通过点击此链接轻松创建它,并且代码是为LinqPad 6编写的,但可以轻松调整(LinqPad 6 使用 .NET Core,但您可以使用 LinqPad 5 进行尝试)非常适合 .NET 框架)。