Supercharging Entity Framework Core: Efficient Bulk Inserts Without Loops or Raw SQL

When working with large datasets in .NET, it's tempting to use foreach loops or raw SQL to insert records. But in Entity Framework Core (EF Core), there's a better way — efficient, clean, and scalable. This guide shows how to handle bulk inserts in EF Core the right way — especially when inserting hundreds or thousands of records. The Common Pitfalls (What NOT to Do) ❌ 1. Insert One-by-One in a Loop foreach (var product in products) { dbContext.Products.Add(product); dbContext.SaveChanges(); // ❌ Very slow, one DB call per insert } Causes N separate database calls Slows down drastically as data grows Risk of transaction bloat and timeouts ❌ 2. Manually Build Raw SQL INSERT INTO Products (Name, Price) VALUES ('A', 10), ('B', 20); -- ❌ Hard to maintain Risk of SQL injection if not parameterized No benefit from EF tracking Difficult to integrate with domain logic The Recommended Approach ✅ Use AddRange() + SaveChanges() var products = new List(); for (int i = 0; i

Jun 27, 2025 - 03:20
 0
Supercharging Entity Framework Core: Efficient Bulk Inserts Without Loops or Raw SQL

When working with large datasets in .NET, it's tempting to use foreach loops or raw SQL to insert records. But in Entity Framework Core (EF Core), there's a better way — efficient, clean, and scalable.

This guide shows how to handle bulk inserts in EF Core the right way — especially when inserting hundreds or thousands of records.

The Common Pitfalls (What NOT to Do)

❌ 1. Insert One-by-One in a Loop

foreach (var product in products)
{
    dbContext.Products.Add(product);
    dbContext.SaveChanges(); // ❌ Very slow, one DB call per insert
}
  • Causes N separate database calls
  • Slows down drastically as data grows
  • Risk of transaction bloat and timeouts

❌ 2. Manually Build Raw SQL

INSERT INTO Products (Name, Price) VALUES ('A', 10), ('B', 20); -- ❌ Hard to maintain
  • Risk of SQL injection if not parameterized
  • No benefit from EF tracking
  • Difficult to integrate with domain logic

The Recommended Approach

✅ Use AddRange() + SaveChanges()

var products = new List<Product>();

for (int i = 0; i < 1000; i++)
{
    products.Add(new Product { Name = $"Product {i}", Price = 10.0m });
}

dbContext.Products.AddRange(products);
await dbContext.SaveChangesAsync(); // ✅ Single batch insert
  • Fast and clean
  • One DB round-trip
  • Works well for up to ~10,000 rows

✅ Handling Very Large Datasets (Chunking)

When inserting more than 10,000 records, chunk your data:

const int batchSize = 500;
var chunks = products.Chunk(batchSize); // .NET 6+

foreach (var chunk in chunks)
{
    dbContext.Products.AddRange(chunk);
    await dbContext.SaveChangesAsync();
    dbContext.ChangeTracker.Clear(); //