Ответ
Метод Update() в DbSet<T> помечает переданную сущность и все её навигационные свойства (которые не null) как изменённые (EntityState.Modified). Это сигнализирует EF Core, что при вызове SaveChanges() для этой сущности должен быть выполнен SQL-запрос UPDATE.
Как это работает:
- Если сущность с таким первичным ключом ещё не отслеживается контекстом, она будет отслеживаться со состоянием
Modified. - Если сущность уже отслеживается,
Update()перезапишет её текущие значения в отслеживаемом объекте. - Все связанные сущности в графе также будут отслеживаться и помечены как
Modified.
Пример обновления:
// Допустим, это данные, пришедшие с клиента (например, из формы редактирования)
var updatedProduct = new Product { Id = 10, Name = "New Monitor", Price = 299.99, CategoryId = 5 };
// Помечаем сущность и все её заполненные свойства как изменённые
context.Products.Update(updatedProduct);
// При SaveChanges() EF Core сгенерирует примерно:
// UPDATE [Products] SET [Name] = @p0, [Price] = @p1, [CategoryId] = @p2
// WHERE [Id] = @p3;
await context.SaveChangesAsync();
Критически важные нюансы:
- Генерируется полный UPDATE: Все свойства сущности будут включены в запрос, даже если фактически изменилось только одно. Это может привести к конфликтам параллелизма и избыточным операциям.
- Для частичного обновления используйте Attach(): Более эффективный паттерн —
Attach()+ явная пометка изменённых свойств.context.Products.Attach(updatedProduct); context.Entry(updatedProduct).Property(p => p.Price).IsModified = true; // Обновляем только цену - Массовые обновления: Для обновления многих строк без их загрузки в память используйте
ExecuteUpdate()(EF Core 7+):await context.Products .Where(p => p.Price < 50) .ExecuteUpdateAsync(setters => setters.SetProperty(p => p.Price, p => p.Price * 1.1));