Inhalt | 7 |
Vorwort | 17 |
Über den Autor | 19 |
1 Einleitung | 21 |
1.1 Programmiersprache in diesem Buch | 21 |
1.2 Fallbeispiele in diesem Buch | 21 |
1.2.1 Entitäten | 22 |
1.3 Anwendungsarten in diesem Buch | 25 |
1.4 Hilfsroutinen zur Konsolenausgabe | 26 |
1.5 Programmcodebeispiel zum Download | 30 |
2 Was ist Entity Framework Core? | 33 |
2.1 Was ist ein Objekt-Relationaler Mapper? | 33 |
2.2 ORM in der .NET-Welt | 35 |
2.3 Versionsgeschichte von Entity Framework Core | 36 |
2.4 Unterstützte Betriebssysteme | 37 |
2.5 Unterstützte .NET-Versionen | 37 |
2.6 Unterstützte Visual Studio-Versionen | 38 |
2.7 Unterstützte Datenbanken | 39 |
2.8 Funktionsumfang von Entity Framework Core | 40 |
2.9 Funktionen, die dauerhaft entfallen | 41 |
2.10 Funktionen, die Microsoft bald nachrüsten will | 41 |
2.11 Hohe Priorität, aber nicht kritisch | 42 |
2.12 Neue Funktionen in Entity Framework Core | 43 |
2.13 Einsatzszenarien | 44 |
3 Installation von Entity Framework Core | 47 |
3.1 Nuget-Pakete | 47 |
3.2 Paketinstallation | 50 |
3.3 Aktualisierung auf eine neue Version | 54 |
4 Konzepte von Entity Framework Core | 59 |
4.1 Vorgehensmodelle bei Entity Framework Core | 59 |
4.2 Artefakte bei Entity Framework Core | 61 |
5 Reverse Engineering bestehender Datenbanken | 63 |
5.1 Reverse Engineering mit PowerShell-Befehlen | 64 |
5.2 Codegenerierung | 67 |
5.3 .NET Core-Tool | 74 |
5.4 Schwächen des Reverse Engineering | 76 |
6 Forward Engineering für neue Datenbanken | 77 |
6.1 Regeln für die selbsterstellten Entitätsklassen | 79 |
6.1.1 Properties | 79 |
6.1.2 Datentypen | 79 |
6.1.3 Beziehungen (Master-Detail) | 79 |
6.1.4 Vererbung | 81 |
6.1.5 Primärschlüssel | 81 |
6.1.6 Beispiele | 81 |
6.2 Regeln für die selbsterstellte Kontextklasse | 84 |
6.2.1 Nuget-Pakete | 84 |
6.2.2 Basisklasse | 85 |
6.2.3 Konstruktor | 85 |
6.2.4 Beispiel | 85 |
6.2.5 Provider und Verbindungszeichenfolge | 86 |
6.2.6 Eigene Verbindungen | 87 |
6.2.7 Thread-Sicherheit | 87 |
6.3 Regeln für die Datenbankschemagenerierung | 87 |
6.4 Beispiel-Client | 88 |
6.5 Anpassung per Fluent-API (OnModelCreating()) | 89 |
6.6 Das erzeugte Datenmodell | 91 |
7 Anpassung des Datenbankschemas | 93 |
7.1 Persistente versus transiente Klassen | 94 |
7.2 Namen im Datenbankschema | 95 |
7.3 Reihenfolge der Spalten in einer Tabelle | 95 |
7.4 Spaltentypen/Datentypen | 96 |
7.5 Pflichtfelder und optionale Felder | 97 |
7.6 Feldlängen | 97 |
7.7 Primärschlüssel | 98 |
7.8 Beziehungen und Fremdschlüssel | 98 |
7.9 Optionale Beziehungen und Pflichtbeziehungen | 99 |
7.10 Uni- und Bidirektionale Beziehungen | 101 |
7.11 1:1-Beziehungen | 102 |
7.12 Indexe festlegen | 103 |
7.13 Weitere Syntaxoptionen für das Fluent-API | 105 |
7.13.1 Sequentielle Konfiguration | 105 |
7.13.2 Strukturierung durch Statement Lambdas | 105 |
7.13.3 Strukturierung durch Unterroutinen | 106 |
7.13.4 Strukturierung durch Konfigurationsklassen | 107 |
7.14 Massenkonfiguration mit dem Fluent-API | 108 |
8 Datenbankschemamigrationen | 111 |
8.1 Anlegen der Datenbank zur Laufzeit | 111 |
8.2 Schemamigrationen zur Entwicklungszeit | 112 |
8.3 Befehle für die Schemamigrationen | 112 |
8.4 ef.exe | 113 |
8.5 Add-Migration | 114 |
8.6 Update-Database | 118 |
8.7 Script-Migration | 119 |
8.8 Weitere Migrationsschritte | 119 |
8.9 Migrationsszenarien | 120 |
8.10 Weitere Möglichkeiten | 121 |
8.11 Schemamigrationen zur Laufzeit | 123 |
9 Daten lesen mit LINQ | 125 |
9.1 Kontextklasse | 125 |
9.2 LINQ-Abfragen | 126 |
9.3 Schrittweises Zusammensetzung von LINQ-Abfragen | 128 |
9.4 Repository-Pattern | 129 |
9.5 Einsatz von var | 130 |
9.6 LINQ-Abfragen mit Paging | 131 |
9.7 Projektionen | 133 |
9.8 Abfrage nach Einzelobjekten | 134 |
9.9 Laden anhand des Primärschlüssels mit Find() | 135 |
9.10 LINQ im RAM statt in der Datenbank | 135 |
9.11 Umgehung für das GroupBy-Problem | 139 |
9.11.1 Mapping auf Nicht-Entitätstypen | 139 |
9.11.2 Entitätsklasse für die Datenbanksicht anlegen | 140 |
9.11.3 Einbinden der Entitätsklasse in die Kontextklasse | 140 |
9.11.4 Verwendung der Pseudo-Entitätsklasse | 141 |
9.11.5 Herausforderung: Migrationen | 141 |
9.11.6 Gruppierungen mit Datenbanksichten | 143 |
9.12 Kurzübersicht über die LINQ-Syntax | 143 |
9.12.1 Einfache SELECT-Befehle (Alle Datensätze) | 145 |
9.12.2 Bedingungen (where) | 145 |
9.12.3 Bedingungen mit Mengen (in) | 146 |
9.12.4 Sortierungen (orderby) | 146 |
9.12.5 Paging (Skip() und Take()) | 147 |
9.12.6 Projektion | 147 |
9.12.7 Aggregatfunktionen (Count(), Min(), Max(), Average(), Sum()) | 148 |
9.12.8 Gruppierungen (GroupBy) | 149 |
9.12.9 Einzelobjekte (SingleOrDefault(), FirstOrDefault()) | 150 |
9.12.10 Verbundene Objekte (Include()) | 151 |
9.12.11 Inner Join (Join) | 152 |
9.12.12 Cross Join (Kartesisches Produkt) | 153 |
9.12.13 Join mit Gruppierung | 153 |
9.12.14 Unter-Abfragen (Sub-Select) | 154 |
10 Objektbeziehungen und Ladestrategien | 157 |
10.1 Standardverhalten | 157 |
10.2 Kein Lazy Loading | 158 |
10.3 Eager Loading | 160 |
10.4 Explizites Nachladen (Explicit Loading) | 163 |
10.5 Preloading mit Relationship Fixup | 165 |
10.6 Details zum Relationship Fixup | 170 |
11 Einfügen, Löschen und Ändern | 171 |
11.1 Speichern mit SaveChanges() | 171 |
11.2 Änderungsverfolgung auch für Unterobjekte | 174 |
11.3 Das Foreach-Problem | 175 |
11.4 Objekte hinzufügen mit Add() | 176 |
11.5 Verbundene Objekte anlegen | 178 |
11.6 Verbundene Objekte ändern/Relationship Fixup | 181 |
11.7 Widersprüchliche Beziehungen | 184 |
11.8 Zusammenfassen von Befehlen (Batching) | 189 |
11.9 Objekte löschen mit Remove() | 190 |
11.10 Löschen mit einem Attrappen-Objekt | 191 |
11.11 Massenlöschen | 192 |
11.12 Datenbanktransaktionen | 193 |
11.13 Change Tracker abfragen | 196 |
11.13.1 Zustand eines Objekts | 196 |
11.13.2 Liste aller geänderten Objekte | 198 |
12 Datenänderungskonflikte (Concurrency) | 201 |
12.1 Rückblick | 201 |
12.2 Im Standard keine Konflikterkennung | 202 |
12.3 Optimistisches Sperren/ Konflikterkennung | 204 |
12.4 Konflikterkennung für alle Eigenschaften | 205 |
12.5 Konflikteinstellung per Konvention | 206 |
12.6 Fallweise Konflikteinstellung | 207 |
12.7 Zeitstempel (Timestamp) | 208 |
12.8 Konflikte auflösen | 210 |
12.9 Pessimistisches Sperren bei Entity Framework Core | 214 |
13 Protokollierung (Logging) | 219 |
13.1 Verwendung der Erweiterungsmethode Log() | 219 |
13.2 Implementierung der Log()-Erweiterungsmethode | 221 |
13.3 Protokollierungskategorien | 224 |
14 Asynchrone Programmierung | 225 |
14.1 Asynchrone Erweiterungsmethoden | 225 |
14.2 ToListAsync() | 225 |
14.3 SaveChangesAsync() | 227 |
14.4 ForeachAsync() | 228 |
15 Dynamische LINQ-Abfragen | 231 |
15.1 Schrittweises Zusammensetzen von LINQ-Abfragen | 231 |
15.2 Expression Trees | 233 |
15.3 Dynamic LINQ | 236 |
16 Daten lesen und ändern mit SQL, Stored Procedures und Table Valued Functions | 239 |
16.1 Abfragen mit FromSql() | 239 |
16.2 Zusammensetzbarkeit von LINQ und SQL | 241 |
16.3 Globale Abfragefilter bei SQL-Abfragen (ab Version 2.0) | 243 |
16.4 Stored Procedures und Table Valued Functions | 244 |
16.5 Globale Abfragefilter bei Stored Procedures und Table Valued Functions | 245 |
16.6 Nicht-Entitätsklassen als Ergebnismenge | 246 |
16.7 SQL-DML-Befehle ohne Resultset | 248 |
17 Weitere Tipps und Tricks zum Mapping | 249 |
17.1 Shadow Properties | 249 |
17.1.1 Automatische Shadow Properties | 249 |
17.1.2 Festlegung eines Shadow Property | 250 |
17.1.3 Ausgabe aller Shadow Properties einer Entitätsklasse | 250 |
17.1.4 Lesen und Ändern eines Shadow Property | 251 |
17.1.5 LINQ-Abfragen mit Shadow Properties | 252 |
17.1.6 Praxisbeispiel: Automatisches Setzen des Shadow Property bei jedem Speichern | 252 |
17.2 Tabellenaufteilung (Table Splitting) | 253 |
17.3 Berechnete Spalten (Computed Columns) | 256 |
17.3.1 Automatisches SELECT | 257 |
17.3.2 Praxistipp: Spalten mit einer Berechnungsformel anlegen | 257 |
17.3.3 Spalten mit einer Berechnungsformel nutzen | 259 |
17.3.4 Spalten mit einer Berechnungsformel beim Reverse Engineering | 261 |
17.4 Standardwerte (Default Values) | 262 |
17.4.1 Standardwerte beim Forward Engineering festlegen | 262 |
17.4.2 Standardwerte verwenden | 263 |
17.4.3 Praxistipp: Standardwerte schon beim Anlegen des Objekts vergeben | 265 |
17.4.4 Standardwerte beim Reverse Engineering | 266 |
17.5 Sequenzobjekte (Sequences) | 267 |
17.5.1 Erstellen von Sequenzen beim Forward Engineering | 267 |
17.5.2 Sequenzen im Einsatz | 268 |
17.6 Alternative Schlüssel | 271 |
17.6.1 Alternative Schlüssel definieren | 272 |
17.6.2 Alternative Schlüssel im Einsatz | 274 |
17.7 Kaskadierendes Löschen (Cascading Delete) | 275 |
17.8 Abbildung von Datenbanksichten (Views) | 278 |
17.8.1 Datenbanksicht anlegen | 279 |
17.8.2 Entitätsklasse für die Datenbanksicht anlegen | 279 |
17.8.3 Einbinden der Entitätsklasse in die Kontextklasse | 279 |
17.8.4 Verwendung der Datenbanksicht | 280 |
17.8.5 Herausforderung: Migrationen | 280 |
18 Weitere Tipps und Tricks zu LINQ | 283 |
18.1 Globale Abfragefilter (ab Version 2.0) | 283 |
18.1.1 Filter definieren | 283 |
18.1.2 Filter nutzen | 284 |
18.1.3 Praxistipp: Filter ignorieren | 285 |
18.2 Zukünftige Abfragen (Future Queries) | 285 |
19 Leistungsoptimierung (Performance Tuning) | 287 |
19.1 Vorgehensmodell zur Leistungsoptimierung bei Entity Framework Core | 287 |
19.2 Best Practices für Ihre eigenen Leistungstests | 288 |
19.3 Leistungsvergleich verschiedener Dattenzugriffstechniken in .NET | 288 |
19.4 Objektzuweisung optimieren | 290 |
19.5 Massenoperationen | 292 |
19.5.1 Einzellöschen | 292 |
19.5.2 Optimierung durch Batching | 293 |
19.5.3 Löschen ohne Laden mit Pseudo-Objekten | 294 |
19.5.4 Einsatz von klassischem SQL anstelle des Entity Framework Core-APIs | 295 |
19.5.5 Lamdba-Ausdrücke für Massenlöschen mit EFPlus | 297 |
19.5.6 Massenaktualisierung mit EFPlus | 298 |
19.6 Leistungsoptimierung durch No-Tracking | 299 |
19.6.1 No-Tracking aktivieren | 300 |
19.6.2 No-Tracking fast immer möglich | 302 |
19.6.3 No-Tracking im änderbaren Datagrid | 305 |
19.6.4 QueryTrackingBehavior und AsTracking() | 306 |
19.6.5 Best Practices | 308 |
19.7 Auswahl der besten Ladestrategie | 308 |
19.8 Zwischenspeicherung (Caching) | 309 |
19.8.1 MemoryCache | 309 |
19.8.2 Abstraktion CacheManager | 312 |
19.9 Second-Level-Caching mit EFPlus | 316 |
19.9.1 Einrichten des Second-Level-Cache | 317 |
19.9.2 Verwenden des Second-Level-Cache | 317 |
20 Softwarearchitektur mit Entity Framework Core | 321 |
20.1 Monolithisches Modell | 321 |
20.2 Entity Framework Core als Datenzugriffsschicht | 322 |
20.3 Reine Geschäftslogik | 324 |
20.4 Geschäftsobjekt- und ViewModel-Klassen | 325 |
20.5 Verteilte Systeme | 326 |
20.6 Fazit | 329 |
21 Zusatzwerkzeuge | 331 |
21.1 Entity Framework Core Power Tools | 331 |
21.1.1 Funktionsüberblick | 331 |
21.1.2 Reverse Engineering mit Entity Framework Core Power Tools | 332 |
21.1.3 Diagramme mit Entity Framework Core Power Tools | 336 |
21.2 LINQPad | 337 |
21.2.1 Aufbau von LINQPad | 338 |
21.2.2 Datenquellen einbinden | 339 |
21.2.3 LINQ-Befehle ausführen | 342 |
21.2.4 Speichern | 345 |
21.2.5 Weitere LINQPad-Treiber | 345 |
21.2.6 Interaktive Programmcodeeingabe | 346 |
21.2.7 Fazit zu LINQPad | 347 |
21.3 Entity Developer | 347 |
21.3.1 Reverse Engineering mit Entity Developer | 348 |
21.3.2 Forward Engineering mit Entity Developer | 359 |
21.4 Entity Framework Profiler | 364 |
21.4.1 Einbinden des Entity Framework Profilers | 366 |
21.4.2 Befehle überwachen mit Entity Framework Profiler | 366 |
21.4.3 Warnungen vor potenziellen Problemen | 369 |
21.4.4 Analysefunktionen | 369 |
21.4.5 Fazit zu Entity Framework Profiler | 370 |
22 Zusatzkomponenten | 371 |
22.1 Entity Framework Plus (EFPlus) | 371 |
22.2 Second-Level-Caching mit EFSecondLevelCache.Core | 372 |
22.3 Objekt-Objekt-Mapping und AutoMapper | 372 |
22.3.1 Objekt-Objekt-Mapping per Reflection | 374 |
22.3.2 AutoMapper | 377 |
22.3.3 Beispiel | 378 |
22.3.4 Abbildungen konfigurieren | 379 |
22.3.5 Abbildung ausführen mit Map() | 380 |
22.3.6 Abbildungskonventionen | 381 |
22.3.7 Profilklassen | 383 |
22.3.8 Verbundene Objekte | 383 |
22.3.9 Manuelle Abbildungen | 384 |
22.3.10 Typkonvertierungen | 386 |
22.3.11 Objektmengen | 388 |
22.3.12 Vererbung | 389 |
22.3.13 Generische Klassen | 391 |
22.3.14 Zusatzaktionen vor und nach dem Mapping | 394 |
22.3.15 Geschwindigkeit | 395 |
22.3.16 Fazit zu AutoMapper | 396 |
23 Praxislösungen | 399 |
23.1 Entity Framework Core in einer ASP.NET Core-Anwendung | 399 |
23.1.1 Das Fallbeispiel “MiracleList“ 379 | 14 |
23.1.2 Architektur | 403 |
23.1.3 Entitätsklassen | 405 |
23.1.4 Entity Framework Core-Kontextklasse | 407 |
23.1.5 Lebensdauer der Kontextklasse in ASP.NET Core-Anwendungen | 409 |
23.1.6 Geschäftslogik | 410 |
23.1.7 WebAPI | 418 |
23.1.8 Verwendung von Entity Framework Core per Dependency Injection | 428 |
23.1.9 Praxistipp: Kontextinstanzpooling (DbContext Pooling) | 431 |
23.2 Entity Framework Core in einer Universal Windows Platform App | 432 |
23.2.1 Das Fallbeispiel “MiracleList Light“ 412 | 15 |
23.2.2 Architektur | 433 |
23.2.3 Entitätsklassen | 435 |
23.2.4 Entity Framework Core-Kontextklasse | 436 |
23.2.5 Startcode | 436 |
23.2.6 Erzeugte Datenbank | 437 |
23.2.7 Datenzugriffscode | 439 |
23.2.8 Benutzeroberfläche | 443 |
23.3 Entity Framework Core in einer Xamarin-Cross-Platform-App | 444 |
23.3.1 Das Fallbeispiel “MiracleList Light“ 424 | 15 |
23.3.2 Architektur | 446 |
23.3.3 Entitätsklassen | 448 |
23.3.4 Entity Framework Core-Kontextklasse | 448 |
23.3.5 Startcode | 450 |
23.3.6 Erzeugte Datenbank | 450 |
23.3.7 Datenzugriffscode | 450 |
23.3.8 Benutzeroberfläche | 454 |
23.4 N:M-Beziehungen zu sich selbst | 455 |
24 Quellen im Internet | 461 |
Index | 463 |
Leere Seite | 2 |