3


Entity Framework 8 raw unmapped types v Dapper




Date Added (UTC):

03 May 2024 @ 00:55

Date Updated (UTC):

03 May 2024 @ 00:55


.NET Version(s):

.NET 8

Tag(s):

#Dapper #DBOperations #EntityFramework


Added By:
Profile Image

Blog   
Ireland    
.NET Developer and tech lead from Ireland!

Benchmark Results:





Benchmark Code:



using BenchmarkDotNet.Attributes;
using Microsoft.EntityFrameworkCore;
using Dapper;
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Linq;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Columns;

public class SportsEvent
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Date { get; set; }
    public string Venue { get; set; }
}

public class SportsEventViewModel : SportsEvent; //unmapped

public class SportsEventContext : DbContext
{
    public DbSet<SportsEvent> SportsEvents { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseSqlServer(@"Server=localhost;Database=TestDB;Trusted_Connection=True;TrustServerCertificate=true");
    }
}

[MemoryDiagnoser]
[Config(typeof(Config))]
[HideColumns(Column.AllocRatio, Column.RatioSD, Column.Median, Column.Gen0, Column.Gen1)]
public class EFDapperUnMappedTypesBenchmark
{
    private const string ConnectionString = 
        @"Server=localhost;Database=TestDB;Trusted_Connection=True;TrustServerCertificate=true";

    private SportsEventContext _context;
    private SqlConnection _connection;

    [GlobalSetup]
    public void Setup()
    {
        _context = new SportsEventContext();
        _connection = new SqlConnection(ConnectionString);

        _context.Database.EnsureDeleted();
        _context.Database.EnsureCreated();

        var events = Enumerable.Range(1, 1000).Select(i => new SportsEvent
        {
            Name = $"Event {i}",
            Date = DateTime.Now.AddDays(i),
            Venue = $"Venue {i}"
        }).ToList();

        _context.SportsEvents.AddRange(events);
        _context.SaveChanges();
    }

    [Benchmark]
    public List<SportsEventViewModel> EF()
    {
        return _context.Database.SqlQueryRaw<SportsEventViewModel>(@"SELECT * FROM SportsEvents").ToList();
    }

    [Benchmark(Baseline = true)]
    public List<SportsEventViewModel> Dapper()
    {
        return _connection.Query<SportsEventViewModel>("SELECT * FROM SportsEvents").ToList();
    }

    private class Config : ManualConfig
    {
        public Config()
        {
            SummaryStyle =
                SummaryStyle.Default
                .WithRatioStyle(RatioStyle.Percentage)
                .WithTimeUnit(Perfolizer.Horology.TimeUnit.Millisecond);
        }
    }
}

// .NET 8 Lowered C# Code unavailable due to errors:
error CS0234: The type or namespace name 'EntityFrameworkCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'Dapper' could not be found (are you missing a using directive or an assembly reference?)
error CS0234: The type or namespace name 'Data' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbSet<>' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbContextOptionsBuilder' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'SqlConnection' could not be found (are you missing a using directive or an assembly reference?)
error CS1061: 'SportsEventContext' does not contain a definition for 'Database' and no accessible extension method 'Database' accepting a first argument of type 'SportsEventContext' could be found (are you missing a using directive or an assembly reference?)
error CS1061: 'SportsEventContext' does not contain a definition for 'SaveChanges' and no accessible extension method 'SaveChanges' accepting a first argument of type 'SportsEventContext' could be found (are you missing a using directive or an assembly reference?)

// .NET 8 IL Code unavailable due to errors:
error CS0234: The type or namespace name 'EntityFrameworkCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'Dapper' could not be found (are you missing a using directive or an assembly reference?)
error CS0234: The type or namespace name 'Data' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbSet<>' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbContextOptionsBuilder' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'SqlConnection' could not be found (are you missing a using directive or an assembly reference?)
error CS1061: 'SportsEventContext' does not contain a definition for 'Database' and no accessible extension method 'Database' accepting a first argument of type 'SportsEventContext' could be found (are you missing a using directive or an assembly reference?)
error CS1061: 'SportsEventContext' does not contain a definition for 'SaveChanges' and no accessible extension method 'SaveChanges' accepting a first argument of type 'SportsEventContext' could be found (are you missing a using directive or an assembly reference?)

// .NET 8 Jit Asm Code unavailable due to errors:
error CS0234: The type or namespace name 'EntityFrameworkCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'Dapper' could not be found (are you missing a using directive or an assembly reference?)
error CS0234: The type or namespace name 'Data' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbSet<>' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbContextOptionsBuilder' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'SqlConnection' could not be found (are you missing a using directive or an assembly reference?)
error CS1061: 'SportsEventContext' does not contain a definition for 'Database' and no accessible extension method 'Database' accepting a first argument of type 'SportsEventContext' could be found (are you missing a using directive or an assembly reference?)
error CS1061: 'SportsEventContext' does not contain a definition for 'SaveChanges' and no accessible extension method 'SaveChanges' accepting a first argument of type 'SportsEventContext' could be found (are you missing a using directive or an assembly reference?)


Benchmark Description:


Since version 8 Entity Frameworks support raw queries to unmapped types (meaning the type is not in DbContext DbSet). Many users liked Dapper for this functionality previous to this EF addition. This benchmark compares Dapper v EF raw unmapped queries. Dapper looks to be about 20% faster.

The setup for the benchmarks involves comparing the performance of querying data from a database using two different approaches in .NET: Entity Framework Core (EF Core) and Dapper. The benchmarks are designed to measure and compare the efficiency of these two popular ORM (Object-Relational Mapping) libraries in terms of data retrieval operations. The .NET version isn't specified directly in the provided code, but given the use of EF Core and Dapper, it's likely targeting .NET Core 3.1 or .NET 5/6, as these versions are commonly used with these libraries. ### General Setup - **Database Context**: A `SportsEventContext` derived from `DbContext` is configured to connect to a SQL Server database (`TestDB`) using a connection string. This context manages the dataset `SportsEvents`. - **Test Data**: In the setup method, the database is first cleared and then recreated. It is then populated with 1,000 `SportsEvent` records, each having a unique name, date, and venue. - **Benchmark Configuration**: The benchmarks use `BenchmarkDotNet`, a powerful library for benchmarking in .NET. Memory diagnostics are enabled (`[MemoryDiagnoser]`), and certain columns like allocation ratio and garbage collection generations are hidden to focus on other metrics. A custom configuration (`Config`) adjusts the summary style to display ratios as percentages and time measurements in milliseconds. ### Benchmarks #### 1. Entity Framework (EF) Benchmark - **Purpose**: This benchmark measures the performance of querying data using Entity Framework Core's raw SQL query capabilities to retrieve and materialize data into a list of `SportsEventViewModel` objects. - **Performance Aspect**: It tests the overhead of EF Core in executing SQL queries, materializing the result set into objects, and the efficiency of its connection management. - **Expected Insights**: Running this benchmark can provide insights into how EF Core performs in scenarios where raw SQL is used instead of LINQ queries, especially in terms of memory usage and execution time. High memory usage or longer execution times may indicate the overhead introduced by EF Core's change tracking and object materialization processes. #### 2. Dapper Benchmark (Baseline) - **Purpose**: This benchmark serves as the baseline for comparison and measures the performance of querying data using Dapper to execute a SQL query and materialize the results into a list of `SportsEventViewModel` objects. - **Performance Aspect**: It focuses on the efficiency of Dapper in executing SQL queries and its ability to quickly materialize data into objects with minimal overhead. - **Expected Insights**: As Dapper is known for its lightweight nature and direct approach to query execution and materialization, this benchmark is expected to show lower memory usage and faster execution times compared to EF Core. This can highlight the performance benefits of using a micro-ORM like Dapper for straightforward data retrieval tasks. ### Conclusion By comparing the results of these two benchmarks, developers can gain valuable insights into the trade-offs between using a full-fledged ORM like EF Core and a micro-ORM like Dapper for data retrieval operations. Specifically, it can help in understanding the impact of these libraries on application performance, especially in scenarios requiring the execution of raw SQL queries and the materialization of query results into objects. The choice between EF Core and Dapper may ultimately depend on the specific requirements of the project, including considerations of performance, ease of use, and feature set.


Benchmark Comments: