Cách truyền thống phải query 100.000 entity về, track hết trong change tracker rồi sinh 100.000 câu UPDATE. Tốn bộ nhớ và round-trip.
ExecuteUpdate dịch thẳng LINQ thành một câu UPDATE duy nhất, không load và không track gì:
csharp
await db.Orders
.Where(o => o.CreatedAt < cutoff && o.Status == OrderStatus.Pending)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.Status, OrderStatus.Expired)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));Ba điểm phải nhớ:
- Chạy ngay lập tức, không đợi
SaveChanges, và không tự mở transaction. Muốn gộp nhiềuExecuteUpdatethành nguyên tử thì tựBeginTransaction. - Không đi qua change tracker. Entity đang được track vẫn giữ giá trị cũ; nếu sau đó gọi
SaveChangestrên chính entity đó, giá trị cũ sẽ ghi đè kết quả bulk. Tránh trộn hai kiểu ghi trên cùng một entity trong một unit of work. - Không có concurrency check tự động. Bù lại nó trả về số dòng bị ảnh hưởng, nên có thể tự kiểm: đưa concurrency token vào
Whererồi so số dòng trả về với 0.
Giới hạn: chỉ update/delete (insert vẫn cần Add + SaveChanges), mỗi lời gọi là một round-trip riêng, và chỉ hỗ trợ provider quan hệ.