ADO.NET vs. EF Core

Ado .NET vs EF Core
Michael W.
01/2026

Performance vs. Produktivität: ADO.NET und EF Core im direkten Vergleich

Die Wahl der richtigen Datenzugriffstechnologie ist entscheidend für Performance, Wartbarkeit und Entwicklungsgeschwindigkeit von .NET‑Anwendungen. ADO.NET und Entity Framework Core (EF Core) repräsentieren dabei zwei grundlegend unterschiedliche Ansätze: ADO.NET bietet direkten, Low‑Level‑Datenbankzugriff mit maximaler Kontrolle, während EF Core als modernes ORM (Object‑Relational Mapping) die Komplexität von Datenbankoperationen abstrahiert.Dieser Artikel betrachtet beide Technologien, vergleicht ihre Stärken und Schwächen anhand konkreter Praxisbeispiele und unterstützt bei der Auswahl der passenden Lösung für zukünftige Projekte.

Kurz‑Einführung zu ADO.NET

ADO.NET ist die fundamentale Datenzugriffstechnologie in .NET, die seit den Anfängen des Frameworks genutzt wird. Sie bietet direkten Zugriff auf Datenbankressourcen über Klassen wie SqlConnection, SqlCommand, SqlDataReader und SqlDataAdapter. Entwickler schreiben SQL‑Queries manuell und haben vollständige Kontrolle über jeden Aspekt der Datenbankinteraktion.

Vorteile:

  • Maximale Performance und minimaler Memory‑Overhead
  • Vollständige Kontrolle über SQL‑Queries
  • Ideal für Stored Procedures und komplexe Datenbanklogik
  • Keine versteckten Abstraktionskosten

Nachteile:

  • Hoher Boilerplate‑Code (Connection‑Management, Mapping)
  • Fehleranfällig durch manuelles Mapping
  • Keine automatischen Migrationen oder Change Tracking

Kurz‑Einführung zu EF Core

Entity Framework Core ist ein leichtgewichtiges, erweiterbares und plattformübergreifendes Open‑Source‑ORM‑Framework der beliebten Entity Framework‑Technologie. EF Core ermöglicht es Entwicklern, mit Datenbanken über stark typisierte C#‑Objekte zu arbeiten, ohne SQL‑Code schreiben zu müssen. Es generiert automatisch SQL‑Queries aus LINQ‑Ausdrücken, verwaltet Beziehungen zwischen Entitäten und bietet Funktionen wie Change Tracking, Migrationen und automatische Schemaerstellung.

Vorteile:

  • Hohe Entwicklerproduktivität durch LINQ und automatisches Mapping
  • Change Tracking und Unit‑of‑Work‑Pattern
  • Code‑First‑Migrationen für Schemaverwaltung
  • Stark typisiert und wartungsfreundlich

Nachteile:

  • Performance‑Overhead durch Abstraktionsschichten
  • Höherer Speicherverbrauch
  • Weniger Kontrolle über generierte SQL‑Queries
  • Lernkurve für komplexe Szenarien

Benchmark‑Setup und Testumgebung

Um Performance‑Unterschiede objektiv zu messen, wurden Benchmarks mit BenchmarkDotNet v0.14.0 auf .NET 9 durchgeführt.

Testumgebung:

  • .NET SDK 9.0.308
  • SQL Server (lokal)
  • Windows 11

Datenmodell:

1[Table("DataModels")]
2 public class DataModel
3 {
4     [Key]
5     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
6     public int Id { get; set; }
7
8     [Required]
9     [MaxLength(100)]
10     public required string Name { get; set; }
11
12     public int Quantity { get; set; }
13 }
14
15DbContext-Konfiguration:
16    public class BenchmarkDbContext : DbContext
17    {
18        private const string ConnectionString =
19"Server=.;Database=BenchmarkDB;Integrated Security=true;TrustServerCertificate=true;";
20
21        public DbSet<DataModel> DataModels { get; set; }
22
23        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
24        {
25            optionsBuilder.UseSqlServer(ConnectionString);
26            optionsBuilder.EnableSensitiveDataLogging(false);
27            optionsBuilder.LogTo(message => { }, Microsoft.Extensions.Logging.LogLevel.None);
28        }
29    }

Das Logging wurde bewusst deaktiviert, um den EF Core-Overhead nichtkünstlich zu erhöhen. Getestet wurden vier Operationen mit jeweils 100, 1.000,10.000 Datensätzen.

Performance‑Vergleich: ReadAll‑Operation

Die ReadAll-Operation liest alle Datensätze aus derDatenbank und materialisiert sie als Liste.

EFCore-Implementierung (mit AsNoTracking):

1[Benchmark(Baseline = true)]
2public List<DataModel> EFCore_ReadAll_NoTracking()
3{
4    return _dbContext.DataModels.AsNoTracking().ToList();
5}
6ADO.NET Implementierung:
7[Benchmark]
8public List<DataModel> AdoNet_ReadAll()
9{
10    var results = new List<DataModel>();
11
12    using (var connection = new SqlConnection(ConnectionString))
13    {
14        connection.Open();
15        var command = new SqlCommand("SELECT Id, Name, Quantity FROM DataModels", connection);
16
17        using (var reader = command.ExecuteReader())
18        {
19            while (reader.Read())
20            {
21                results.Add(new DataModel
22                {
23                    Id = reader.GetInt32(0),
24                    Name = reader.GetString(1),
25                    Quantity = reader.GetInt32(2)
26                });
27            }
28        }
29    }
30
31    return results;
32}

Ergebnisse:

RecordCount EF Core (μs) ADO.NET (μs) Performance-Faktor EF Core Memory ADO.NET Memory
100 126.83 117.74 1.08x 34.34 KB 12.95 KB
1,000 395.60 355.76 1.11x 287.48 KB 97.33 KB
10,000 6,260.71 4,320.47 1.45x 2,918.4 KB 1,040.74 KB

Performance-Vergleich: SingleById-Operation

Das Abrufen eines einzelnen Datensatzes nach ID ist einehäufige Operation in Web-Anwendungen.

EF Core Implementierung:

1[Benchmark]
2public DataModel? EFCore_SingleById()
3{
4    int targetId = RecordCount / 2;
5    return _dbContext.DataModels
6        .AsNoTracking()
7        .FirstOrDefault(d => d.Id == targetId);
8}
910ADO.NET Implementierung:
11[Benchmark]
12public DataModel? AdoNet_SingleById()
13{
14    int targetId = RecordCount / 2;
15
16    using (var connection = new SqlConnection(ConnectionString))
17    {
18        connection.Open();
19        var command = new SqlCommand(
20            "SELECT Id, Name, Quantity FROM DataModels WHERE Id = @Id",
21            connection);
22        command.Parameters.AddWithValue("@Id", targetId);
23
24        using (var reader = command.ExecuteReader())
25        {
26            if (reader.Read())
27            {
28                return new DataModel
29                {
30                    Id = reader.GetInt32(0),
31                    Name = reader.GetString(1),
32                    Quantity = reader.GetInt32(2)
33                };
34            }
35        }
36    }
37    return null;
38}

Ergebnisse:

RecordCount EF Core (μs) ADO.NET (μs) Performance-Faktor EF Core Memory ADO.NET Memory
100 98.21 78.59 1.25x 10.13 KB 4.15 KB
1,000 89.19 77.29 1.15x 10.13 KB 4.15 KB
10,000 197.29 115.10 1.71x 10.13 KB 4.15 KB

ADO.NET ist konsistent schneller, besonders beigrößeren Tabellen (71% Speedup bei 10.000 Datensätzen). <dieSpeicherallokation ist mit 4,15 KB vs. 10,13 KB deutlich geringer – einwichtiger Faktor bei High-Frequency-Operationen wie API-Endpoints.

Performance-Vergleich: InsertSingle-Operation

EF-Core-Implementierung:

1[Benchmark]
2public void EFCore_InsertSingle()
3{
4    using (var context = new BenchmarkDbContext())
5    {
6        var model = new DataModel
7        {
8            Name = "TestInsert",
9            Quantity = 999
10        };
11        context.DataModels.Add(model);
12        context.SaveChanges();
13
14        context.DataModels.Remove(model);
15        context.SaveChanges();
16    }
17}

ADO.NET-Implementierung:

1[Benchmark]
2public void AdoNet_InsertSingle()
3{
4    int insertedId;
5
6    using (var connection = new SqlConnection(ConnectionString))
7    {
8        connection.Open();
9
10        var insertCmd = new SqlCommand(
11            "INSERT INTO DataModels (Name, Quantity) OUTPUT INSERTED.Id VALUES (@Name, @Quantity)",
12            connection);
13        insertCmd.Parameters.AddWithValue("@Name", "TestInsert");
14        insertCmd.Parameters.AddWithValue("@Quantity", 999);
15        insertedId = (int)insertCmd.ExecuteScalar();
16
17        var deleteCmd = new SqlCommand("DELETE FROM DataModels WHERE Id = @Id", connection);
18        deleteCmd.Parameters.AddWithValue("@Id", insertedId);
19        deleteCmd.ExecuteNonQuery();
20    }
21}

Ergebnisse:

RecordCount EF Core (μs) ADO.NET (μs) Performance-Faktor EF Core Memory ADO.NET Memory
100 1,358.19 424.71 3.20x 111.9 KB 5.22 KB
1,000 1,745.87 379.68 4.60x 111.9 KB 5.22 KB
10,000 2,245.39 1,050.88 2.14x 111.9 KB 5.22 KB

ADO.NET ist 2-5x schneller und benötigt 95% wenigerSpeicher. Der EF Core-Overhead entsteht durch Context-Initialisierung, ChangeTracking und zwei SaveChanges() Aufrufe. Für Bulk-Inserts oderLogging-Operationen ist ADO.NET klar überlegen.

Performance-Vergleich: UpdateSingle-Operation

EF Core-Implementierung:

1[Benchmark]
2public void EFCore_UpdateSingle()
3{
4    using (var context = new BenchmarkDbContext())
5    {
6        int targetId = RecordCount / 2;
7        var model = context.DataModels.Find(targetId);
8        if (model != null)
9        {
10            model.Quantity = 12345;
11            context.SaveChanges();
12
13            model.Quantity = targetId * 10;
14            context.SaveChanges();
15        }
16    }
17}

ADO.NET-Implementierung:

1[Benchmark]
2public void AdoNet_UpdateSingle()
3{
4    int targetId = RecordCount / 2;
5
6    using (var connection = new SqlConnection(ConnectionString))
7    {
8        connection.Open();
9
10        var updateCmd = new SqlCommand(
11            "UPDATE DataModels SET Quantity = @Quantity WHERE Id = @Id",
12            connection);
13        updateCmd.Parameters.AddWithValue("@Id", targetId);
14        updateCmd.Parameters.AddWithValue("@Quantity", 12345);
15        updateCmd.ExecuteNonQuery();
16
17        var resetCmd = new SqlCommand(
18            "UPDATE DataModels SET Quantity = @Quantity WHERE Id = @Id",
19            connection);
20        resetCmd.Parameters.AddWithValue("@Id", targetId);
21        resetCmd.Parameters.AddWithValue("@Quantity", targetId * 10);
22        resetCmd.ExecuteNonQuery();
23    }
24}

Ergebnisse:

RecordCount EF Core (μs) ADO.NET (μs) Performance-Faktor EF Core Memory ADO.NET Memory
100 1,580.68 471.49 3.35x 123.06 KB 4.74 KB
1,000 1,819.21 409.08 4.45x 123.06 KB 4.74 KB
10,000 2,781.23 537.05 5.18x 123.06 KB 4.74 KB

ADO.NET ist bis zu 5.18x schneller bei 10.000Datensätzen und verbraucht 96% weniger Speicher. EF Core muss hier denDatensatz laden, tracken und zwei Mal SaveChanges() durchführen - einerheblicher Overhead für einfache Updates.

Best Practices und Empfehlungen

Nutzen Sie EF Core, wenn:

  • CRUD‑Operationen mit komplexen Objektgraphen durchgeführt werden
  • Entwicklerproduktivität und Wartbarkeit im Vordergrund stehen
  • Code‑First‑Migrationen erforderlich sind
  • Datenmengen moderat (< 1.000 Datensätze pro Request) sind
  • Entitäten‑Beziehungen navigiert werden müssen

Nutzen Sie ADO.NET, wenn:

  • Performance‑kritische Operationen mit hohem Durchsatz erforderlich sind
  • Volle Kontrolle über SQL‑Queries nötig ist
  • Speichereffizienz kritisch ist
  • Einzelne Writes mit minimaler Latenz durchgeführt werden
  • Bulk‑Operationen (> 10.000 Datensätze) ausgeführt werden

Hybrid‑Ansatz:

  • EF Core für Standard‑CRUD und Geschäftslogik
  • ADO.NET für Performance‑Hotspots
  • Dapper als leichter Mittelweg
  • Gemeinsame Connection‑Nutzung zwischen EF Core und ADO.NET möglich

Fazit

Die Benchmarks zeigen eindeutig: ADO.NET ist bei allen Operationen schneller und speichereffizienter als EF Core. Der Performance‑Vorteil reicht von 8 % bei kleinen Read‑All‑Operationen bis zu über 500 % bei großen Updates. Gleichzeitig ist der Speicherverbrauch bei ADO.NET durchweg deutlich niedriger.

Für typische Business‑Anwendungen ist EF Core aufgrund höherer Entwicklerproduktivität, Wartbarkeit und Typsicherheit meist die richtige Wahl, da Performance‑Unterschiede im Bereich von Mikrosekunden im Vergleich zu Netzwerk‑Latenz und Rendering‑Zeiten vernachlässigbar sind.

Empfehlung: Starten Sie mit EF Core und optimieren Sie gezielt mit ADO.NET, sobald Profiling konkrete Performance‑Bottlenecks aufzeigt. Ein pragmatischer Hybrid‑Ansatz kombiniert die Vorteile beider Technologien.

Nutzen Sie BenchmarkDotNet, um die Performance‑Charakteristik Ihrer eigenen Anwendung zu messen. Die dargestellten Benchmarks dienen als Ausgangspunkt – individuelle Datenmodelle, Queries und Hardware können zu anderen Ergebnissen führen. Messen Sie, bevor Sie optimieren!

No items found.
Foto von Michael
Michael W.

Mehr zum Thema

Pfeil nach rechts (Verlinkung)
12/2025

Architekturentscheidungen mit EF Core Architektur

Blauer Pfeil nach rechts (Verlinkung)
EF Core: Owned & Complex Types für saubere Datenmodellierung
05/2024

Entity Framework Owned Types | ComplexType C# Tutorial

Blauer Pfeil nach rechts (Verlinkung)
Entity Framework CRUD: Datenbankoperationen in .NET effizient umsetzen
06/2020

Entity Framework Tutorial | .NET CRUD Operationen Guide

Blauer Pfeil nach rechts (Verlinkung)
No items found.

Lassen Sie uns gemeinsam wachsen.

Devware GmbH verpflichtet sich, Ihre Privatsphäre zu schützen. Wir benötigen Ihre Kontaktinformationen, um Sie bezüglich unserer Produkte und Dienstleistungen zu kontaktieren. Mit Klick auf Absenden geben Sie sich damit einverstanden. Weitere Informationen finden Sie unter Datenschutz. Ihre Daten behandeln wir vertraulich. Versprochen.
Vielen Dank für Ihr Vertrauen.
Unser Team prüft Ihre Anfrage sorgfältig und meldet sich in der Regel innerhalb von 48 Stunden bei Ihnen zurück.
Falls es besonders eilig ist, erreichen Sie uns auch telefonisch:
+ 49 (0) 202 478 269 0.
Da ist etwas schief gegangen beim Absenden des Formulars.