Ответ
Метод Add() в Entity Framework Core отслеживает новую сущность, помечая ее для вставки (INSERT) в базу данных. Сама вставка происходит не сразу, а при следующем вызове SaveChanges() или SaveChangesAsync().
Как это работает:
- Вы вызываете
DbSet<T>.Add(entity)илиDbContext.Add(entity). - EF Core начинает отслеживать эту сущность и устанавливает ее состояние (
EntityState) вAdded. - При вызове
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().
Как это в жизни выглядит:
- Ты вызываешь
DbSet<T>.Add(entity)илиDbContext.Add(entity). - EF Core берёт эту сущность, ставит на ней штамп
Addedи начинает за ней следить. - Когда ты вызываешь
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, там скорость вообще другая.