⚡ Key Takeaways: Insert, update, and delete thousands of records efficiently with EF Core Bulk extensions. 100x faster than standard SaveChanges.
Entity Framework Core is great for single operations. For bulk operations, it’s painfully slow. Bulk extensions fix this.
❌ The Problem
// ❌ 100,000 records - Each tracked individually
var products = GenerateProducts(100000);
foreach (var product in products)
{
context.Products.Add(product); // ❌ 100,000 Add operations
}
await context.SaveChangesAsync(); // ❌ 100,000 INSERT statements!
// Time: 25 seconds | Memory: 450MB | DB Calls: 100,000
✅ The Solution
dotnet add package EFCore.BulkExtensions
// ✅ Bulk insert - Single operation var products = GenerateProducts(100000); await context.BulkInsertAsync(products); // Time: 2.5 seconds | Memory: 80MB | DB Calls: 1 // 10x faster, 5x less memory!
💡 Advanced Bulk Operations
// ✅ 1. Bulk Update with conditions
await context.BulkUpdateAsync(
products,
options => options
.SetProperty(p => p.Price, p => p.Price * 1.1m)
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow)
);
// ✅ 2. Bulk Delete with filter
await context.Products
.Where(p => p.IsActive == false)
.BatchDeleteAsync();
// ✅ 3. Bulk Insert or Update (Upsert)
await context.BulkInsertOrUpdateAsync(products);
// ✅ 4. Merge (Insert/Update/Delete)
await context.BulkInsertOrUpdateOrDeleteAsync(
products,
options => options
.SetOutputIdentity = true
.SetProperties = new List<string> { nameof(Product.Price), nameof(Product.Stock) }
);
// ✅ 5. Bulk Read with performance
var chunkSize = 1000;
var chunks = products.Chunk(chunkSize);
foreach (var chunk in chunks)
{
await context.BulkInsertAsync(chunk); // Process in chunks
}
📊 Performance Comparison
| Operation | Records | SaveChanges | Bulk Extensions |
|---|---|---|---|
| Insert | 10,000 | 3.2s | 0.3s |
| Insert | 100,000 | 25.0s | 2.5s |
| Update | 10,000 | 2.8s | 0.4s |
| Delete | 10,000 | 2.1s | 0.2s |
