The key methods for adding entities via the DbSet are
Add<TEntity>(TEntity entity)AddRange<TEntity>(IEnumerable<TEntity> entities)AddRange<TEntity>(params TEntity[] entities)
Most often, you will see examples of the generic version of Add but with the type, parameter omitted because the compiler will infer it. The following two examples are identical:
// with the type parameter
var author = new Author{ FirstName = "William", LastName = "Shakespeare" };
context.Authors.Add<Author>(author);
// without a type parameter
var author = new Author{ FirstName = "William", LastName = "Shakespeare" };
context.Authors.Add(author);
The context begins tracking the entity that was passed into the Add method and applies an EntityState value of Added to it. The context also applies the same EntityState value of Added to all other objects in the object graph that aren't already being tracked by the context. In the next example, the Added state is also applied to the books:
var context = new SampleContext();
var author = new Author {
FirstName = "William",
LastName = "Shakespeare",
Books = new List<Book>
{
new Book { Title = "Hamlet"},
new Book { Title = "Othello" },
new Book { Title = "Macbeth" }
}
};
context.Authors.Add(author);
The books are added because they are referenced through the Books property of the author. In the next example, the books will not be added:
var author = new Author { FirstName = "William", LastName = "Shakespeare" };
var hamlet = new Book { Title = "Hamlet", Author = author };
var othello = new Book { Title = "Othello", Author = author };
var macbeth = new Book { Title = "Macbeth", Author = author };
context.Authors.Add(author);
context.SaveChanges();
Although the author has been assigned to the Author property of each of the books that have been instantiated, the author entity is unaware of these relationships. Its Books property is still null and the books are not added to the context.
Adding Multiple Records
The AddRange method is used for adding multiple objects to the ChangeTracker in one method call. The code in the next example is very similar to the previous example, but the AddRange method is used to add all the books and the author to the ChangeTracker in one go:
var context = new SampleContext();
var author = new Author { FirstName = "Stephen", LastName = "King" };
var books = new List<Book> {
new Book { Title = "It", Author = author },
new Book { Title = "Carrie", Author = author },
new Book { Title = "Misery", Author = author }
};
context.Books.AddRange(books);
context.SaveChanges();
The AddRange method takes an IEnumerable<object>. The author forms part of the object graph for at least one of the books, so it is added too.
The other version of the AddRange method takes a params array of entities, providing the facility to add a variable number of entities to the database without the need to create a collection for them:
var context = new SampleContext();
var author = new Author { FirstName = "William", LastName = "Shakespeare" };
var hamlet = new Book { Title = "Hamlet", Author = author };
var othello = new Book { Title = "Othello", Author = author };
var macbeth = new Book { Title = "Macbeth", Author = author };
context.Books.AddRange(hamlet, othello, macbeth);
context.SaveChanges();
When the SaveChanges method is called on the DbContext, all entities with an EntityState of Added will be inserted into the database. The ordering of the SQL to insert objects is managed in such a way to ensure that principals are inserted first and their primary key value is then available to be applied to the foreign key of dependent objects.
⚠️ Common Misconception: AddRange is NOT a Bulk Insert
It’s important to understand that AddRange is not the same as a bulk insert.
AddRangeonly adds multiple entities into the Change Tracker.When you call
SaveChanges(), EF Core will insert them into the database.- In earlier versions, this happened strictly one by one.
- In EF Core 7 and later, inserts are batched together to reduce round-trips — but they’re still executed as multiple individual
INSERTstatements.
This means it’s much better than before, but still not designed for true high-performance bulk operations.
If you need to insert thousands or millions of rows efficiently, you should use the BulkInsert method from Entity Framework Extensions.
// Using AddRange (EF Core 7+, batched inserts but still individual INSERT statements)
context.Books.AddRange(books);
context.SaveChanges();
// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;
// Using BulkInsert (true bulk operation, single optimized command under the hood)
context.BulkInsert(books);