這個指令還是會把所有的資料 Select 出來,再更新
原指令:
UPDATE Job Set En_Status = 200 Where En_Status = 100 and LastTouchAt < '2023-05-06 12:34:56'
其中 '2023-05-06 12:34:56' 是 DateTime.Now.AddMinutes(-2) 的結果(Web Server 端的時間扣 2 分鐘)
但,若是改使用 UpdateFromQueryAsync 如下:
var c = await Ds.NewContext.GvContext.Jobs.Where(j => j.En_Status == Cst.Job.Status.Running && j.LastTouchAt < DateTime.Now.AddMinutes(-2))
.UpdateFromQueryAsync(j => new Ds.Gv.Job { En_Status = Cst.Job.Status.ReStarting });
產生的 SQL 如下:
UPDATE A
SET A.[En_Status] = @zzz_BatchUpdate_0
FROM [Job] AS A
INNER JOIN ( SELECT [j].[Id], [j].[CancelledAt], [j].[CancelledBy], [j].[En_Status], [j].[EndAt], [j].[Exception], [j].[Filename], [j].[InformationJson], [j].[InitAt], [j].[Is_CheckOnly], [j].[LastTouchAt], [j].[LastTouchMessage], [j].[LoopStartAt], [j].[Name], [j].[ScheduleId], [j].[TotalTouch], [j].[TouchCount]
FROM [Job] AS [j]
WHERE [j].[En_Status] = 100 AND [j].[LastTouchAt] < DATEADD(minute, CAST(-2.0E0 AS int), GETDATE())
) AS B ON A.[Id] = B.[Id]
有兩個要注意的地方:
1. 它會先 Select 全欄位,再做更新
2. 它的時間是 DB Server 的現在時間。不是 Web Server 端的時間。
順便記錄一下。若是要執行 Update xx Ser cc = cc + 1 Where ...
EF 可寫為:
var c = await Ds.NewContext.GvContext.Jobs.Where(j => j.En_Status == Cst.Job.Status.Running && j.LastTouchAt < DateTime.Now.AddMinutes(-2))
.UpdateFromQueryAsync(j => new Ds.Gv.Job { TotalTouch = j.TotalTouch + 1 });
轉換的 SQL 為:
UPDATE A
SET A.[TotalTouch] = B.[TotalTouch] + 1
FROM [Job] AS A
INNER JOIN ( SELECT [j].[Id], [j].[CancelledAt], [j].[CancelledBy], [j].[En_Status], [j].[EndAt], [j].[Exception], [j].[Filename], [j].[InformationJson], [j].[InitAt], [j].[Is_CheckOnly], [j].[LastTouchAt], [j].[LastTouchMessage], [j].[LoopStartAt], [j].[Name], [j].[ScheduleId], [j].[TotalTouch], [j].[TouchCount]
FROM [Job] AS [j]
WHERE [j].[En_Status] = 100 AND [j].[LastTouchAt] < DATEADD(minute, CAST(-2.0E0 AS int), GETDATE())
) AS B ON A.[Id] = B.[Id]