using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
public static List<BenchmarkResult> BenchmarkResults = new List<BenchmarkResult>();
public static void Main()
using (var context = new EntityContext())
context.Database.EnsureCreated();
var orders = GenerateOrders(1000, 5);
var clockSaveChanges = new Stopwatch();
var clockBulkInsert = new Stopwatch();
var clockBulkInsertOptimized = new Stopwatch();
using (var context = new EntityContext())
context.Orders.AddRange(orders);
clockSaveChanges.Start();
BenchmarkResults.Add(new BenchmarkResult() { Action = "SaveChanges (EF)", Entities = orders.Count, Performance = clockSaveChanges.ElapsedMilliseconds + " ms" });
using (var context = new EntityContext())
context.BulkInsert(orders, options => options.IncludeGraph = true);
var timeFaster = Math.Round((double)clockSaveChanges.ElapsedMilliseconds / clockBulkInsert.ElapsedMilliseconds, 2);
var reducedPercent = Math.Round((double)(clockSaveChanges.ElapsedMilliseconds - clockBulkInsert.ElapsedMilliseconds) / clockSaveChanges.ElapsedMilliseconds, 2) * 100;
BenchmarkResults.Add(new BenchmarkResult() { Action = "BulkInsert + IncludeGraph", Entities = orders.Count, Performance = $"{clockBulkInsert.ElapsedMilliseconds} ms", TimeFaster = $"{timeFaster}x faster than SaveChanges", ReducedPercent = $"Time reduced by {reducedPercent}% compared to SaveChanges" });
using (var context = new EntityContext())
clockBulkInsertOptimized.Start();
context.BulkInsertOptimized(orders, options => options.IncludeGraph = true);
clockBulkInsertOptimized.Stop();
var timeFaster = Math.Round((double)clockSaveChanges.ElapsedMilliseconds / clockBulkInsertOptimized.ElapsedMilliseconds, 2);
var reducedPercent = Math.Round((double)(clockSaveChanges.ElapsedMilliseconds - clockBulkInsertOptimized.ElapsedMilliseconds) / clockSaveChanges.ElapsedMilliseconds, 2) * 100;
BenchmarkResults.Add(new BenchmarkResult() { Action = "BulkInsertOptimized + IncludeGraph", Entities = orders.Count, Performance = $"{clockBulkInsertOptimized.ElapsedMilliseconds} ms", TimeFaster = $"{timeFaster}x faster than SaveChanges", ReducedPercent = $"Time reduced by {reducedPercent}% compared to SaveChanges" });
FiddleHelper.WriteTable(BenchmarkResults);
public static void JustInTime_Compile()
var orders = GenerateOrders(20, 5);
using (var context = new EntityContext())
context.Orders.AddRange(orders);
context.BulkDelete(orders, options => options.IncludeGraph = true);
using (var context = new EntityContext())
context.BulkInsert(orders, options => options.IncludeGraph = true);
context.BulkDelete(orders, options => options.IncludeGraph = true);
using (var context = new EntityContext())
context.BulkInsertOptimized(orders, options => options.IncludeGraph = true);
context.BulkDelete(orders, options => options.IncludeGraph = true);
public static List<Order> GenerateOrders(int count, int itemCount)
var list = new List<Order>();
for(int i = 0; i < count; i++)
var order = new Order() { Items = new List<OrderItem>() };
for(int j = 0; j < itemCount; j++)
order.Items.Add(new OrderItem());
public class EntityContext : DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
optionsBuilder.UseSqlServer(new SqlConnection(FiddleHelper.GetConnectionStringSqlServer()));
base.OnConfiguring(optionsBuilder);
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
public int OrderID { get; set; }
public List<OrderItem> Items { get; set; }
public string Column1 { get; set; }
public string Column2 { get; set; }
public string Column3 { get; set; }
public string Column4 { get; set; }
public string Column5 { get; set; }
public string Column6 { get; set; }
public string Column7 { get; set; }
public string Column8 { get; set; }
public string Column9 { get; set; }
public int OrderItemID { get; set; }
public string Column1 { get; set; }
public string Column2 { get; set; }
public string Column3 { get; set; }
public string Column4 { get; set; }
public string Column5 { get; set; }
public string Column6 { get; set; }
public string Column7 { get; set; }
public string Column8 { get; set; }
public string Column9 { get; set; }
public class BenchmarkResult
public string Action { get; set; }
public int Entities { get; set; }
public string Performance { get; set; }
public string TimeFaster { get; set; }
public string ReducedPercent { get; set; }