如何在 Dapper 中使用一条 sql 语句传递多条记录进行更新
How to pass multiple records to update with one sql statement in Dapper
我正在尝试使用一个 Update 语句来更新具有不同值的多个记录(我并没有尝试将许多行更新为具有相同的值,这是非常简单的)。这是我现在正在尝试的:
using (var cn = GetOpenConnection()) {
// get items where we need to set calculated fields that will now be persisted in the DB
var items = cn.Query<MaintenanceItem>("select TOP 500 * from [Maintenance] where Tolerance IS NOT NULL");
foreach (var mi in maintItems)
{
// Set calculated fields on multiple recrods
logic.CalculateToleranceFields(mi, true);
}
var updateInput = items.Select(a => new {a.ToleranceMonths, a.ToleranceDays, a.ToleranceHours, a.ToleranceLandings, a.ToleranceCycles, a.ToleranceRIN }).ToList();
// THIS DOESN'T WORK - attempting to update multiple rows with different values
var numResults = cn.Execute(@"UPDATE rm
SET rm.ToleranceMonths=ur.ToleranceMonths,
rm.ToleranceDays=ur.ToleranceDays,
rm.ToleranceHours=ur.ToleranceHours,
rm.ToleranceLandings=ur.ToleranceLandings,
rm.ToleranceCycles=ur.ToleranceCycles,
rm.ToleranceRIN=ur.ToleranceRIN
from [RoutineItems] rm
Inner Join @UpdatedRecords ur ON rm.AircraftId=ur.AircraftId AND rm.ItemNumber=ur.ItemNumber", updateInput);
Assert.IsTrue(numResults == maintItems.Count());
}
Dapper 可以进行这种批量更新吗?我宁愿批量更新而不是使用 for 循环将数据推送到数据库中。
看起来这在 Dapper 中目前是不可能的。在考虑需要在幕后做什么才能实现这一点时,这是完全可以理解的。
我最终做的是使用 3 条语句创建一个临时文件 table,将需要更新的数据填充到其中,然后使用内部连接调用一个更新到我的临时文件 table:
cn.Execute(@"create table #routineUpdatedRecords
(
AircraftId int,
ItemNumber int,
ToleranceMonths int,
ToleranceDays int,
ToleranceLandings int,
ToleranceCycles decimal(12,2),
ToleranceRIN decimal(12,2),
ToleranceHours decimal(12,2)
);");
cn.Execute(@"Insert INTO #routineUpdatedRecords
VALUES(@AircraftId, @ItemNumber, @ToleranceMonths, @ToleranceDays,
@ToleranceLandings, @ToleranceCycles, @ToleranceRIN, @ToleranceHours)", updateInput);
var numResults = cn.Execute(@"UPDATE rm
SET rm.ToleranceMonths=ur.ToleranceMonths,
rm.ToleranceDays=ur.ToleranceDays,
rm.ToleranceHours=ur.ToleranceHours,
rm.ToleranceLandings=ur.ToleranceLandings,
rm.ToleranceCycles=ur.ToleranceCycles,
rm.ToleranceRIN=ur.ToleranceRIN
from [RoutineItems] rm
Inner Join #routineUpdatedRecords ur ON rm.AircraftId=ur.AircraftId AND rm.ItemNumber=ur.ItemNumber");
我相信这比在循环中调用更新要快,因为我正在更新大约 60 万行。
我知道线程有点旧。但是你可以这样做,而不是使用 temp table 。提供了更好的语法。
string sql = @"UPDATE rm
SET rm.ToleranceMonths=@ToleranceMonths,
rm.ToleranceDays=@ToleranceDays,
rm.ToleranceHours=@ToleranceHours,
rm.ToleranceLandings=@ToleranceLandings,
rm.ToleranceCycles=@ToleranceCycles,
rm.ToleranceRIN=@ToleranceRIN
FROM [RoutineItems] rm
WHERE rm.AircraftId=@AircraftId AND rm.ItemNumber=@ItemNumber
";
var numResults = cn.Execute(sql, updateInput);
我正在尝试使用一个 Update 语句来更新具有不同值的多个记录(我并没有尝试将许多行更新为具有相同的值,这是非常简单的)。这是我现在正在尝试的:
using (var cn = GetOpenConnection()) {
// get items where we need to set calculated fields that will now be persisted in the DB
var items = cn.Query<MaintenanceItem>("select TOP 500 * from [Maintenance] where Tolerance IS NOT NULL");
foreach (var mi in maintItems)
{
// Set calculated fields on multiple recrods
logic.CalculateToleranceFields(mi, true);
}
var updateInput = items.Select(a => new {a.ToleranceMonths, a.ToleranceDays, a.ToleranceHours, a.ToleranceLandings, a.ToleranceCycles, a.ToleranceRIN }).ToList();
// THIS DOESN'T WORK - attempting to update multiple rows with different values
var numResults = cn.Execute(@"UPDATE rm
SET rm.ToleranceMonths=ur.ToleranceMonths,
rm.ToleranceDays=ur.ToleranceDays,
rm.ToleranceHours=ur.ToleranceHours,
rm.ToleranceLandings=ur.ToleranceLandings,
rm.ToleranceCycles=ur.ToleranceCycles,
rm.ToleranceRIN=ur.ToleranceRIN
from [RoutineItems] rm
Inner Join @UpdatedRecords ur ON rm.AircraftId=ur.AircraftId AND rm.ItemNumber=ur.ItemNumber", updateInput);
Assert.IsTrue(numResults == maintItems.Count());
}
Dapper 可以进行这种批量更新吗?我宁愿批量更新而不是使用 for 循环将数据推送到数据库中。
看起来这在 Dapper 中目前是不可能的。在考虑需要在幕后做什么才能实现这一点时,这是完全可以理解的。
我最终做的是使用 3 条语句创建一个临时文件 table,将需要更新的数据填充到其中,然后使用内部连接调用一个更新到我的临时文件 table:
cn.Execute(@"create table #routineUpdatedRecords
(
AircraftId int,
ItemNumber int,
ToleranceMonths int,
ToleranceDays int,
ToleranceLandings int,
ToleranceCycles decimal(12,2),
ToleranceRIN decimal(12,2),
ToleranceHours decimal(12,2)
);");
cn.Execute(@"Insert INTO #routineUpdatedRecords
VALUES(@AircraftId, @ItemNumber, @ToleranceMonths, @ToleranceDays,
@ToleranceLandings, @ToleranceCycles, @ToleranceRIN, @ToleranceHours)", updateInput);
var numResults = cn.Execute(@"UPDATE rm
SET rm.ToleranceMonths=ur.ToleranceMonths,
rm.ToleranceDays=ur.ToleranceDays,
rm.ToleranceHours=ur.ToleranceHours,
rm.ToleranceLandings=ur.ToleranceLandings,
rm.ToleranceCycles=ur.ToleranceCycles,
rm.ToleranceRIN=ur.ToleranceRIN
from [RoutineItems] rm
Inner Join #routineUpdatedRecords ur ON rm.AircraftId=ur.AircraftId AND rm.ItemNumber=ur.ItemNumber");
我相信这比在循环中调用更新要快,因为我正在更新大约 60 万行。
我知道线程有点旧。但是你可以这样做,而不是使用 temp table 。提供了更好的语法。
string sql = @"UPDATE rm
SET rm.ToleranceMonths=@ToleranceMonths,
rm.ToleranceDays=@ToleranceDays,
rm.ToleranceHours=@ToleranceHours,
rm.ToleranceLandings=@ToleranceLandings,
rm.ToleranceCycles=@ToleranceCycles,
rm.ToleranceRIN=@ToleranceRIN
FROM [RoutineItems] rm
WHERE rm.AircraftId=@AircraftId AND rm.ItemNumber=@ItemNumber
";
var numResults = cn.Execute(sql, updateInput);