Что делает метод Add() в Entity Framework Core?

Ответ

Метод Add() в Entity Framework Core отслеживает новую сущность, помечая ее для вставки (INSERT) в базу данных. Сама вставка происходит не сразу, а при следующем вызове SaveChanges() или SaveChangesAsync().

Как это работает:

  1. Вы вызываете DbSet<T>.Add(entity) или DbContext.Add(entity).
  2. EF Core начинает отслеживать эту сущность и устанавливает ее состояние (EntityState) в Added.
  3. При вызове SaveChanges() EF Core генерирует и выполняет соответствующий SQL-запрос INSERT.

Пример базового использования:

using var context = new BloggingContext();

var newBlog = new Blog { Url = "https://example.com" };
context.Blogs.Add(newBlog); // Состояние сущности newBlog становится 'Added'

// В этот момент INSERT в БД еще НЕ выполнен
Console.WriteLine(context.Entry(newBlog).State); // Выведет: Added

// INSERT выполняется здесь
int recordsAffected = await context.SaveChangesAsync();
Console.WriteLine($"Добавлено записей: {recordsAffected}");

Важные особенности и альтернативы:

  • Каскадное добавление: Если у новой сущности есть связанные сущности в навигационных свойствах, и эти связи настроены (например, Required), они также будут помечены как Added и вставлены каскадно.
  • AddRange(): Для добавления коллекции сущностей эффективнее использовать AddRange(), чтобы минимизировать накладные расходы на отслеживание.
    context.Blogs.AddRange(blog1, blog2, blog3);
  • Проверка существования: Add() не проверяет, существует ли уже такая сущность в БД. Если добавить сущность с тем же первичным ключом, который уже отслеживается, будет выброшено исключение.
  • Производительность: Для массовой вставки тысяч записей Add()/SaveChanges() неэффективен. Используйте AddRange() с одной SaveChanges() или специализированные библиотеки вроде EFCore.BulkExtensions или SqlBulkCopy.

Ответ 18+ 🔞

А, ну так, метод Add() в Entity Framework Core — это типа флажок «вот эту штуку запихни в базу, когда будет время». Он её не пихает сразу, а просто помечает для вставки. Сама вставка случится только когда ты скажешь «окей, поехали» через SaveChanges().

Как это в жизни выглядит:

  1. Ты вызываешь DbSet<T>.Add(entity) или DbContext.Add(entity).
  2. EF Core берёт эту сущность, ставит на ней штамп Added и начинает за ней следить.
  3. Когда ты вызываешь SaveChanges(), EF Core генерирует SQL-запрос INSERT и отправляет его в базу.

Простой пример, чтоб было понятно:

using var context = new BloggingContext();

var newBlog = new Blog { Url = "https://example.com" };
context.Blogs.Add(newBlog); // Сущность newBlog теперь помечена как 'Added'

// В этот момент в базу ещё НИЧЕГО не ушло!
Console.WriteLine(context.Entry(newBlog).State); // Выведет: Added

// А вот теперь — да, пошла вставка
int recordsAffected = await context.SaveChangesAsync();
Console.WriteLine($"Добавлено записей: {recordsAffected}");

А теперь про подводные камни, блядь:

  • Каскадное добавление: Если у твоей новой сущности есть прицепленные к ней другие сущности (в навигационных свойствах), и связи настроены правильно (например, как Required), то EF Core их тоже автоматом пометит как Added и вставит всё пачкой. Удобно, но иногда неожиданно.
  • AddRange(): Если тебе надо добавить не одну, а целую пачку сущностей, не вызывай Add() в цикле, ёпта. Используй AddRange() — так EF Core меньше дергается и работает быстрее.
    context.Blogs.AddRange(blog1, blog2, blog3);
  • Проверки нет: Add() — он тупой как пробка. Он не проверяет, есть ли уже такая же запись в базе. Если ты попробуешь добавить сущность с таким же первичным ключом, который он уже отслеживает, он тебе выбросит исключение. Сам дурак.
  • Производительность: Если тебе надо впендюрить в базу не десяток, а тысячи записей, то Add()/SaveChanges() — это пиздец какой медленный способ. Для таких дел есть или AddRange() с одним вызовом SaveChanges(), или специальные библиотеки вроде EFCore.BulkExtensions. А для совсем уж диких объёмов смотри в сторону SqlBulkCopy, там скорость вообще другая.