Last active
October 29, 2024 12:33
-
-
Save ozzie-eu/6af55841cd34c44d894b4e0b469e298f to your computer and use it in GitHub Desktop.
.NET console application to compare EF Core and Dapper performance running against the Wide World Importers sample database.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Dapper; | |
using Microsoft.EntityFrameworkCore; | |
using System.Data.SqlClient; | |
using System.Diagnostics; | |
namespace WideWorldImportersPerformanceBenchmark | |
{ | |
public class WideWorldImportersContext : DbContext | |
{ | |
public DbSet<Orders> Orders { get; set; } | |
public DbSet<Customers> Customers { get; set; } | |
public DbSet<OrderLines> OrderLines { get; set; } | |
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | |
{ | |
optionsBuilder.UseSqlServer(Environment.GetEnvironmentVariable("CONNECTION_STRING")); | |
} | |
protected override void OnModelCreating(ModelBuilder modelBuilder) | |
{ | |
modelBuilder.HasDefaultSchema("sales"); | |
modelBuilder.Entity<Orders>() | |
.HasKey(o => o.OrderID); | |
modelBuilder.Entity<Customers>() | |
.HasKey(c => c.CustomerID); | |
modelBuilder.Entity<OrderLines>() | |
.HasKey(ol => new { ol.OrderID, ol.StockItemID }); | |
modelBuilder.Entity<Orders>() | |
.HasOne(o => o.Customer) | |
.WithMany() // No navigation property in Customer | |
.HasForeignKey(o => o.CustomerID); | |
modelBuilder.Entity<OrderLines>() | |
.HasOne(ol => ol.Order) | |
.WithMany(o => o.OrderLines) | |
.HasForeignKey(ol => ol.OrderID); | |
} | |
} | |
public class Orders | |
{ | |
public int OrderID { get; set; } | |
public int CustomerID { get; set; } | |
public DateTime OrderDate { get; set; } | |
public Customers Customer { get; set; } | |
public List<OrderLines> OrderLines { get; set; } = new(); | |
} | |
public class Customers | |
{ | |
public int CustomerID { get; set; } | |
public string CustomerName { get; set; } | |
} | |
public class OrderLines | |
{ | |
public int OrderID { get; set; } | |
public int StockItemID { get; set; } | |
public decimal UnitPrice { get; set; } | |
public int Quantity { get; set; } | |
public Orders Order { get; set; } | |
} | |
class Program | |
{ | |
static async Task Main(string[] args) | |
{ | |
using var context = new WideWorldImportersContext(); | |
using var connection = new SqlConnection(Environment.GetEnvironmentVariable("CONNECTION_STRING")); | |
await BenchmarkEFCore(context); | |
await BenchmarkDapper(connection); | |
} | |
static async Task BenchmarkEFCore(WideWorldImportersContext context) | |
{ | |
var stopwatch = new Stopwatch(); | |
stopwatch.Start(); | |
var orders = await context.Orders | |
.Include(o => o.Customer) | |
.Include(o => o.OrderLines) | |
.ToListAsync(); | |
stopwatch.Stop(); | |
Console.WriteLine($"EF Core execution time: {stopwatch.ElapsedMilliseconds} ms"); | |
} | |
static async Task BenchmarkDapper(SqlConnection connection) | |
{ | |
var stopwatch = new Stopwatch(); | |
stopwatch.Start(); | |
var sql = @" | |
SELECT o.*, c.*, ol.* | |
FROM Sales.Orders o | |
INNER JOIN Sales.Customers c ON o.CustomerID = c.CustomerID | |
INNER JOIN Sales.OrderLines ol ON o.OrderID = ol.OrderID"; | |
var orders = (await connection.QueryAsync<Orders, Customers, OrderLines, Orders>(sql, | |
(o, c, ol) => | |
{ | |
o.Customer = c; | |
o.OrderLines.Add(ol); | |
return o; | |
}, splitOn: "CustomerID, OrderID")) | |
.ToList(); | |
stopwatch.Stop(); | |
Console.WriteLine($"Dapper execution time: {stopwatch.ElapsedMilliseconds} ms"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The program has dependencies on the following packages: