Titelei
Impressum
Inhalt
Vorwort
Über den Autor
1 Einleitung
1.1 Programmiersprache in diesem Buch
1.2 Fallbeispiele in diesem Buch
1.2.1 Entitäten
1.3 Anwendungsarten in diesem Buch
1.4 Hilfsroutinen zur Konsolenausgabe
1.5 Programmcodebeispiel zum Download
2 Was ist Entity Framework Core?
2.1 Was ist ein Objekt-Relationaler Mapper?
2.2 ORM in der .NET-Welt
2.3 Versionsgeschichte von Entity Framework Core
2.4 Unterstützte Betriebssysteme
2.5 Unterstützte .NET-Versionen
2.6 Unterstützte Visual Studio-Versionen
2.7 Unterstützte Datenbanken
2.8 Funktionsumfang von Entity Framework Core
2.9 Funktionen, die dauerhaft entfallen
2.10 Funktionen, die Microsoft bald nachrüsten will
2.11 Hohe Priorität, aber nicht kritisch
2.12 Neue Funktionen in Entity Framework Core
2.13 Einsatzszenarien
3 Installation von Entity Framework Core
3.1 Nuget-Pakete
3.2 Paketinstallation
3.3 Aktualisierung auf eine neue Version
4 Konzepte von Entity Framework Core
4.1 Vorgehensmodelle bei Entity Framework Core
4.2 Artefakte bei Entity Framework Core
5 Reverse Engineering bestehender Datenbanken
5.1 Reverse Engineering mit PowerShell-Befehlen
5.2 Codegenerierung
5.3 .NET Core-Tool
5.4 Schwächen des Reverse Engineering
6 Forward Engineering für neue Datenbanken
6.1 Regeln für die selbsterstellten Entitätsklassen
6.1.1 Properties
6.1.2 Datentypen
6.1.3 Beziehungen (Master-Detail)
6.1.4 Vererbung
6.1.5 Primärschlüssel
6.1.6 Beispiele
6.2 Regeln für die selbsterstellte Kontextklasse
6.2.1 Nuget-Pakete
6.2.2 Basisklasse
6.2.3 Konstruktor
6.2.4 Beispiel
6.2.5 Provider und Verbindungszeichenfolge
6.2.6 Eigene Verbindungen
6.2.7 Thread-Sicherheit
6.3 Regeln für die Datenbankschemagenerierung
6.4 Beispiel-Client
6.5 Anpassung per Fluent-API (OnModelCreating())
6.6 Das erzeugte Datenmodell
7 Anpassung des Datenbankschemas
7.1 Persistente versus transiente Klassen
7.2 Namen im Datenbankschema
7.3 Reihenfolge der Spalten in einer Tabelle
7.4 Spaltentypen/Datentypen
7.5 Pflichtfelder und optionale Felder
7.6 Feldlängen
7.7 Primärschlüssel
7.8 Beziehungen und Fremdschlüssel
7.9 Optionale Beziehungen und Pflichtbeziehungen
7.10 Uni- und Bidirektionale Beziehungen
7.11 1:1-Beziehungen
7.12 Indexe festlegen
7.13 Weitere Syntaxoptionen für das Fluent-API
7.13.1 Sequentielle Konfiguration
7.13.2 Strukturierung durch Statement Lambdas
7.13.3 Strukturierung durch Unterroutinen
7.13.4 Strukturierung durch Konfigurationsklassen
7.14 Massenkonfiguration mit dem Fluent-API
8 Datenbankschemamigrationen
8.1 Anlegen der Datenbank zur Laufzeit
8.2 Schemamigrationen zur Entwicklungszeit
8.3 Befehle für die Schemamigrationen
8.4 ef.exe
8.5 Add-Migration
8.6 Update-Database
8.7 Script-Migration
8.8 Weitere Migrationsschritte
8.9 Migrationsszenarien
8.10 Weitere Möglichkeiten
8.11 Schemamigrationen zur Laufzeit
9 Daten lesen mit LINQ
9.1 Kontextklasse
9.2 LINQ-Abfragen
9.3 Schrittweises Zusammensetzung von LINQ-Abfragen
9.4 Repository-Pattern
9.5 Einsatz von var
9.6 LINQ-Abfragen mit Paging
9.7 Projektionen
9.8 Abfrage nach Einzelobjekten
9.9 Laden anhand des Primärschlüssels mit Find()
9.10 LINQ im RAM statt in der Datenbank
9.11 Umgehung für das GroupBy-Problem
9.11.1 Mapping auf Nicht-Entitätstypen
9.11.2 Entitätsklasse für die Datenbanksicht anlegen
9.11.3 Einbinden der Entitätsklasse in die Kontextklasse
9.11.4 Verwendung der Pseudo-Entitätsklasse
9.11.5 Herausforderung: Migrationen
9.11.6 Gruppierungen mit Datenbanksichten
9.12 Kurzübersicht über die LINQ-Syntax
9.12.1 Einfache SELECT-Befehle (Alle Datensätze)
9.12.2 Bedingungen (where)
9.12.3 Bedingungen mit Mengen (in)
9.12.4 Sortierungen (orderby)
9.12.5 Paging (Skip() und Take())
9.12.6 Projektion
9.12.7 Aggregatfunktionen (Count(), Min(), Max(), Average(), Sum())
9.12.8 Gruppierungen (GroupBy)
9.12.9 Einzelobjekte (SingleOrDefault(), FirstOrDefault())
9.12.10 Verbundene Objekte (Include())
9.12.11 Inner Join (Join)
9.12.12 Cross Join (Kartesisches Produkt)
9.12.13 Join mit Gruppierung
9.12.14 Unter-Abfragen (Sub-Select)
10 Objektbeziehungen und Ladestrategien
10.1 Standardverhalten
10.2 Kein Lazy Loading
10.3 Eager Loading
10.4 Explizites Nachladen (Explicit Loading)
10.5 Preloading mit Relationship Fixup
10.6 Details zum Relationship Fixup
11 Einfügen, Löschen und Ändern
11.1 Speichern mit SaveChanges()
11.2 Änderungsverfolgung auch für Unterobjekte
11.3 Das Foreach-Problem
11.4 Objekte hinzufügen mit Add()
11.5 Verbundene Objekte anlegen
11.6 Verbundene Objekte ändern/Relationship Fixup
11.7 Widersprüchliche Beziehungen
11.8 Zusammenfassen von Befehlen (Batching)
11.9 Objekte löschen mit Remove()
11.10 Löschen mit einem Attrappen-Objekt
11.11 Massenlöschen
11.12 Datenbanktransaktionen
11.13 Change Tracker abfragen
11.13.1 Zustand eines Objekts
11.13.2 Liste aller geänderten Objekte
12 Datenänderungskonflikte (Concurrency)
12.1 Rückblick
12.2 Im Standard keine Konflikterkennung
12.3 Optimistisches Sperren/Konflikterkennung
12.4 Konflikterkennung für alle Eigenschaften
12.5 Konflikteinstellung per Konvention
12.6 Fallweise Konflikteinstellung
12.7 Zeitstempel (Timestamp)
12.8 Konflikte auflösen
12.9 Pessimistisches Sperren bei Entity Framework Core
13 Protokollierung (Logging)
13.1 Verwendung der Erweiterungsmethode Log()
13.2 Implementierung der Log()-Erweiterungsmethode
13.3 Protokollierungskategorien
14 Asynchrone Programmierung
14.1 Asynchrone Erweiterungsmethoden
14.2 ToListAsync()
14.3 SaveChangesAsync()
14.4 ForeachAsync()
15 Dynamische LINQ-Abfragen
15.1 Schrittweises Zusammensetzen von LINQ-Abfragen
15.2 Expression Trees
15.3 Dynamic LINQ
16 Daten lesen und ändern mit SQL, Stored Procedures und Table Valued Functions
16.1 Abfragen mit FromSql()
16.2 Zusammensetzbarkeit von LINQ und SQL
16.3 Globale Abfragefilter bei SQL-Abfragen (ab Version 2.0)
16.4 Stored Procedures und Table Valued Functions
16.5 Globale Abfragefilter bei Stored Procedures und Table Valued Functions
16.6 Nicht-Entitätsklassen als Ergebnismenge
16.7 SQL-DML-Befehle ohne Resultset
17 Weitere Tipps und Tricks zum Mapping
17.1 Shadow Properties
17.1.1 Automatische Shadow Properties
17.1.2 Festlegung eines Shadow Property
17.1.3 Ausgabe aller Shadow Properties einer Entitätsklasse
17.1.4 Lesen und Ändern eines Shadow Property
17.1.5 LINQ-Abfragen mit Shadow Properties
17.1.6 Praxisbeispiel: Automatisches Setzen des Shadow Property bei jedem Speichern
17.2 Tabellenaufteilung (Table Splitting)
17.3 Berechnete Spalten (Computed Columns)
17.3.1 Automatisches SELECT
17.3.2 Praxistipp: Spalten mit einer Berechnungsformel anlegen
17.3.3 Spalten mit einer Berechnungsformel nutzen
17.3.4 Spalten mit einer Berechnungsformel beim Reverse Engineering
17.4 Standardwerte (Default Values)
17.4.1 Standardwerte beim Forward Engineering festlegen
17.4.2 Standardwerte verwenden
17.4.3 Praxistipp: Standardwerte schon beim Anlegen des Objekts vergeben
17.4.4 Standardwerte beim Reverse Engineering
17.5 Sequenzobjekte (Sequences)
17.5.1 Erstellen von Sequenzen beim Forward Engineering
17.5.2 Sequenzen im Einsatz
17.6 Alternative Schlüssel
17.6.1 Alternative Schlüssel definieren
17.6.2 Alternative Schlüssel im Einsatz
17.7 Kaskadierendes Löschen (Cascading Delete)
17.8 Abbildung von Datenbanksichten (Views)
17.8.1 Datenbanksicht anlegen
17.8.2 Entitätsklasse für die Datenbanksicht anlegen
17.8.3 Einbinden der Entitätsklasse in die Kontextklasse
17.8.4 Verwendung der Datenbanksicht
17.8.5 Herausforderung: Migrationen
18 Weitere Tipps und Tricks zu LINQ
18.1 Globale Abfragefilter (ab Version 2.0)
18.1.1 Filter definieren
18.1.2 Filter nutzen
18.1.3 Praxistipp: Filter ignorieren
18.2 Zukünftige Abfragen (Future Queries)
19 Leistungsoptimierung (Performance Tuning)
19.1 Vorgehensmodell zur Leistungsoptimierung bei Entity Framework Core
19.2 Best Practices für Ihre eigenen Leistungstests
19.3 Leistungsvergleich verschiedener Dattenzugriffstechniken in .NET
19.4 Objektzuweisung optimieren
19.5 Massenoperationen
19.5.1 Einzellöschen
19.5.2 Optimierung durch Batching
19.5.3 Löschen ohne Laden mit Pseudo-Objekten
19.5.4 Einsatz von klassischem SQL anstelle des Entity Framework Core-APIs
19.5.5 Lamdba-Ausdrücke für Massenlöschen mit EFPlus
19.5.6 Massenaktualisierung mit EFPlus
19.6 Leistungsoptimierung durch No-Tracking
19.6.1 No-Tracking aktivieren
19.6.2 No-Tracking fast immer möglich
19.6.3 No-Tracking im änderbaren Datagrid
19.6.4 QueryTrackingBehavior und AsTracking()
19.6.5 Best Practices
19.7 Auswahl der besten Ladestrategie
19.8 Zwischenspeicherung (Caching)
19.8.1 MemoryCache
19.8.2 Abstraktion CacheManager
19.9 Second-Level-Caching mit EFPlus
19.9.1 Einrichten des Second-Level-Cache
19.9.2 Verwenden des Second-Level-Cache
20 Softwarearchitektur mit Entity Framework Core
20.1 Monolithisches Modell
20.2 Entity Framework Core als Datenzugriffsschicht
20.3 Reine Geschäftslogik
20.4 Geschäftsobjekt- und ViewModel-Klassen
20.5 Verteilte Systeme
20.6 Fazit
21 Zusatzwerkzeuge
21.1 Entity Framework Core Power Tools
21.1.1 Funktionsüberblick
21.1.2 Reverse Engineering mit Entity Framework Core Power Tools
21.1.3 Diagramme mit Entity Framework Core Power Tools
21.2 LINQPad
21.2.1 Aufbau von LINQPad
21.2.2 Datenquellen einbinden
21.2.3 LINQ-Befehle ausführen
21.2.4 Speichern
21.2.5 Weitere LINQPad-Treiber
21.2.6 Interaktive Programmcodeeingabe
21.2.7 Fazit zu LINQPad
21.3 Entity Developer
21.3.1 Reverse Engineering mit Entity Developer
21.3.2 Forward Engineering mit Entity Developer
21.4 Entity Framework Profiler
21.4.1 Einbinden des Entity Framework Profilers
21.4.2 Befehle überwachen mit Entity Framework Profiler
21.4.3 Warnungen vor potenziellen Problemen
21.4.4 Analysefunktionen
21.4.5 Fazit zu Entity Framework Profiler
22 Zusatzkomponenten
22.1 Entity Framework Plus (EFPlus)
22.2 Second-Level-Caching mit EFSecondLevelCache.Core
22.3 Objekt-Objekt-Mapping und AutoMapper
22.3.1 Objekt-Objekt-Mapping per Reflection
22.3.2 AutoMapper
22.3.3 Beispiel
22.3.4 Abbildungen konfigurieren
22.3.5 Abbildung ausführen mit Map()
22.3.6 Abbildungskonventionen
22.3.7 Profilklassen
22.3.8 Verbundene Objekte
22.3.9 Manuelle Abbildungen
22.3.10 Typkonvertierungen
22.3.11 Objektmengen
22.3.12 Vererbung
22.3.13 Generische Klassen
22.3.14 Zusatzaktionen vor und nach dem Mapping
22.3.15 Geschwindigkeit
22.3.16 Fazit zu AutoMapper
23 Praxislösungen
23.1 Entity Framework Core in einer ASP.NET Core-Anwendung
23.1.1 Das Fallbeispiel „MiracleList“
23.1.2 Architektur
23.1.3 Entitätsklassen
23.1.4 Entity Framework Core-Kontextklasse
23.1.5 Lebensdauer der Kontextklasse in ASP.NET Core-Anwendungen
23.1.6 Geschäftslogik
23.1.7 WebAPI
23.1.8 Verwendung von Entity Framework Core per Dependency Injection
23.1.9 Praxistipp: Kontextinstanzpooling (DbContext Pooling)
23.2 Entity Framework Core in einer Universal Windows Platform App
23.2.1 Das Fallbeispiel „MiracleList Light“
23.2.2 Architektur
23.2.3 Entitätsklassen
23.2.4 Entity Framework Core-Kontextklasse
23.2.5 Startcode
23.2.6 Erzeugte Datenbank
23.2.7 Datenzugriffscode
23.2.8 Benutzeroberfläche
23.3 Entity Framework Core in einer Xamarin-Cross-Platform-App
23.3.1 Das Fallbeispiel „MiracleList Light“
23.3.2 Architektur
23.3.3 Entitätsklassen
23.3.4 Entity Framework Core-Kontextklasse
23.3.5 Startcode
23.3.6 Erzeugte Datenbank
23.3.7 Datenzugriffscode
23.3.8 Benutzeroberfläche
23.4 N:M-Beziehungen zu sich selbst
24 Quellen im Internet
Holger Schwichtenberg
Effizienter Datenzugriff mit Entity Framework Core
Datenbankprogrammierung mit C#
für .NET Framework, .NET Core und
Xamarin
Alle in diesem Buch enthaltenen Informationen, Verfahren und Darstellungen wurden nach bestem Wissen zusammengestellt und mit Sorgfalt getestet. Dennoch sind Fehler nicht ganz auszuschließen. Aus diesem Grund sind die im vorliegenden Buch enthaltenen Informationen mit keiner Verpflichtung oder Garantie irgendeiner Art verbunden. Autor und Verlag übernehmen infolgedessen keine juristische Verantwortung und werden keine daraus folgende oder sonstige Haftung übernehmen, die auf irgendeine Art aus der Benutzung dieser Informationen – oder Teilen davon – entsteht.
Ebenso übernehmen Autor und Verlag keine Gewähr dafür, dass beschriebene Verfahren usw. frei von Schutzrechten Dritter sind. Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Buch berechtigt deshalb auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen und MarkenschutzGesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften.
Bibliografische Information der Deutschen Nationalbibliothek: Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.
Dieses Werk ist urheberrechtlich geschützt. Alle Rechte, auch die der Übersetzung, des Nachdruckes und der Vervielfältigung des Buches, oder Teilen daraus, vorbehalten. Kein Teil des Werkes darf ohne schriftliche Genehmigung des Verlages in irgendeiner Form (Fotokopie, Mikrofilm oder ein anderes Verfahren) – auch nicht für Zwecke der Unterrichtsgestaltung – reproduziert oder unter Verwendung elektronischer Systeme verarbeitet, vervielfältigt oder verbreitet werden.
© 2018 Carl Hanser Verlag München
www.hanser-fachbuch.de
Lektorat: Sylvia Hasselbach
Copyediting: Matthias Bloch, Essen
Umschlagdesign: Marc Müller-Bremer, München, www.rebranding.de
Umschlagrealisation: Stephan Rönigk
Print-ISBN 978-3-446-44898-8
E-Book-ISBN 978-3-446-44978-7
Verwendete Schriften: SourceSansPro und SourceCodePro (Lizenz)
CSS-Version: 1.0
Font License | Zurück zum Impressum |
Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. "Reserved Font Name" refers to any names specified as such after the copyright statement(s). "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. TERMINATION This license becomes null and void if any of the above conditions are not met. DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Vorwort |
Liebe Leserinnen und Leser,
ich nutze Entity Framework in echten Softwareentwicklungsprojekten seit der allerersten Version, also seit der Version 1.0 von ADO.NET Entity Framework im Jahr 2008. Zuvor hatte ich einen selbstentwickelten Objekt-Relationalen Mapper in meinen Projekten verwendet. Entity Framework Core ist das Nachfolgeprodukt, das es seit 2016 gibt. Ich setzte seitdem auch (aber nicht ausschließlich) Entity Framework Core in der Praxis ein. Viele Projekte laufen noch mit dem klassischen Entity Framework.
Microsoft entwickelt Entity Framework Core inkrementell, d. h. die Versionen 1.x und 2.x stellen zunächst eine in vielen Punkten noch unvollständige Grundversion dar, die in den Folgeversionen dann komplettiert wird.
Dieses inkrementelle Konzept habe ich auch mit diesem Buch umgesetzt. Das Buch ist seit September 2016 in mehreren Versionen erschienen. Die vor Ihnen liegende Version dieses Buchs beschreibt nun alle Kernaspekte und viele Tipps und Tricks sowie Praxisszenarien zu Entity Framework Core. Ich plane, in Zukunft weitere Versionen dieses Buchs zu veröffentlichen, die die kommenden Versionen von Entity Framework Core beschreiben und auch weitere Tipps & Tricks sowie Praxisszenarien ergänzen.
Da Fachbücher leider heutzutage nicht nennenswert dazu beitragen können, den Lebensunterhalt meiner Familie zu bestreiten, ist dieses Projekt ein Hobby. Dementsprechend kann ich nicht garantieren, wann es Updates zu diesem Buch geben wird. Ich werde dann an diesem Buch arbeiten, wenn ich neben meinem Beruf als Softwarearchitekt, Berater und Dozent und meinen sportlichen Betätigungen noch etwas Zeit für das Fachbuchautorenhobby übrig habe.
Zudem möchte ich darauf hinweisen, dass ich natürlich keinen kostenfreien technischen Support zu den Inhalten dieses Buchs geben kann. Ich freue mich aber immer über konstruktives Feedback und Verbesserungsvorschläge. Bitte verwenden Sie dazu das Kontaktformular auf www.dotnet-doktor.de.
Wenn Sie technische Hilfe zu Entity Framework und Entity Framework Core oder anderen Themen rund um .NET, Visual Studio, Windows oder andere Microsoft-Produkte benötigen, stehe ich Ihnen im Rahmen meiner beruflichen Tätigkeit für die Firmen www.IT-Visions.de (Beratung, Schulung, Support) und 5Minds IT-Solutions GmbH & Co KG (Softwareentwicklung, siehe www.5minds.de) gerne zur Verfügung. Bitte wenden Sie sich für ein Angebot an das jeweilige Kundenteam.
Die Beispiele zu diesem Buch können Sie herunterladen auf der von mir ehrenamtlich betriebenen Leser-Website unter www.IT-Visions.de/Leser. Dort müssen Sie sich registrieren. Bei der Registrierung wird ein Losungswort abgefragt. Bitte geben Sie dort Ascension ein.
Herzliche Grüße aus Essen, dem Herzen der Metropole Ruhrgebiet
Holger Schwichtenberg
Über den Autor |
Studienabschluss Diplom-Wirtschaftsinformatik an der Universität Essen
Promotion an der Universität Essen im Gebiet komponentenbasierter Softwareentwicklung
Seit 1996 selbstständig als unabhängiger Berater, Dozent, Softwarearchitekt und Fachjournalist
Leiter des Berater- und Dozententeams
bei www.IT-Visions.de
Leitung der Softwareentwicklung im Bereich Microsoft/.NET
bei der 5minds IT-Solutions GmbH & Co. KG (www.5minds.de)
Über 65 Fachbücher beim Carl Hanser Verlag, bei O’Reilly, Microsoft Press und Addison-Wesley sowie mehr als 950 Beiträge in Fachzeitschriften
Gutachter in den Wettbewerbsverfahren der EU gegen Microsoft (2006-2009)
Ständiger Mitarbeiter der Zeitschriften iX (seit 1999), dotnetpro (seit 2000) und Windows Developer (seit 2010) sowie beim Online-Portal heise.de (seit 2008)
Regelmäßiger Sprecher auf nationalen und internationalen Fachkonferenzen (z. B. Microsoft TechEd, Microsoft Summit, Microsoft IT Forum, BASTA, BASTA-on-Tour, .NET Architecture Camp, Advanced Developers Conference, Developer Week, OOP, DOTNET Cologne, MD DevDays, Community in Motion, DOTNET-Konferenz, VS One, NRW.Conf, Net.Object Days, Windows Forum, Container Conf)
Zertifikate und Auszeichnungen von Microsoft:
Microsoft Most Valuable Professional (MVP)
Microsoft Certified Solution Developer (MCSD)
Thematische Schwerpunkte:
Softwarearchitektur, mehrschichtige Softwareentwicklung, Softwarekomponenten, SOA
Microsoft .NET Framework, Visual Studio, C#, Visual Basic
.NET-Architektur/Auswahl von .NET-Technologien
Einführung von .NET Framework und Visual Studio/Migration auf .NET
Webanwendungsentwicklung und Cross-Plattform-Anwendungen mit HTML, ASP.NET, JavaScript/TypeScript und Webframeworks wie Angular
Enterprise .NET, verteilte Systeme/Webservices mit .NET, insbesondere Windows Communication Foundation und WebAPI
Relationale Datenbanken, XML, Datenzugriffsstrategien
Objektrelationales Mapping (ORM), insbesondere ADO.NET Entity Framework und EF Core
Windows PowerShell, PowerShell Core und Windows Management Instrumentation (WMI)
Ehrenamtliche Community-Tätigkeiten:
Vortragender für die International .NET Association (INETA)
Betrieb diverser Community-Websites: www.dotnetframework.de, www.entwickler-lexikon.de, www.windows-scripting.de, www.aspnetdev.de u. a.
Firmenwebsites: http://www.IT-Visions.de und http://www.5minds.de
Weblog: http://www.dotnet-doktor.de
Kontakt: E-Mail buero@IT-Visions.de sowie Telefon 0201-64 95 90-0
1 | Einleitung |
1.1 | Programmiersprache in diesem Buch |
Als Programmiersprache kommt in diesem Buch C# zum Einsatz, weil dies die bei weitem am häufigsten verwendete Programmiersprache in .NET ist. Der Autor dieses Buchs programmiert in einigen Kundenprojekten .NET-Anwendungen zwar auch in Visual Basic .NET, leider bietet dieses Buch jedoch nicht den Raum, alle Listings in beiden Sprachen wiederzugeben.
Eine Sprachkonvertierung zwischen C# und Visual Basic .NET ist im WWW kostenfrei verfügbar auf der Website http://converter.telerik.com.
1.2 | Fallbeispiele in diesem Buch |
Die meisten Beispielprogrammcodes in diesem Buch drehen sich um das Fallbeispiel der fiktiven Fluggesellschaft „World Wide Wings“, abgekürzt WWWings (siehe auch www.world-wide-wings.de).
Bild 1.1 Logo der fiktiven Fluggesellschaft „World Wide Wings“
HINWEIS: In einzeln Unterkapitel werden andere Fallbeispiele verwendet (z. B. die Aufgabenverwaltung „MiracleList“). Diese Fallbeispiele werden dann in den jeweiligen Kapiteln erläutert.
1.2.1 | Entitäten |
Im Anwendungsfall „World Wide Wings“ geht es um folgende Entitäten:
Flüge zwischen zwei Orten, bei denen die Orte bewusst nicht als eigene Entität modelliert wurden, sondern Zeichenketten sind (dies vereinfacht das Verständnis vieler Beispiele)
Passagiere, die auf Flügen fliegen
Mitarbeiter der Fluggesellschaft, die wiederum Vorgesetzte haben, die auch Mitarbeiter sind
Piloten als eine Spezialisierung von Mitarbeitern
Personen als Sammlung der gemeinsamen Eigenschaften für alle Menschen in diesem Beispiel. Personen gibt es aber nicht eigenständig, sondern nur in den Ausprägungen/Spezialisierungen Passagier, Mitarbeiter und Pilot. Im objektorientierten Sinne ist Person also eine abstrakte Basisklasse, die keine Instanzen besitzen kann, sondern nur der Vererbung dient.
Es gibt zwei Datenmodelle:
Das etwas einfachere Modell #1 ist das Ergebnis klassischen relationalen Datenbankdesigns mit Normalisierung. Das Objektmodell daraus entsteht per Reverse Engineering.
Modell #2 ist das Ergebnis des Forward Engineering mit Entity Framework Core aus einem Objektmodell. Zusätzlich gibt es hier weitere Entitäten (Persondetail, Flugzeugtyp und Flugzeugtypdetail), um weitere Modellierungsaspekte aufzeigen zu können.
In Modell #1 gibt es eine jeweils eigene Tabelle für Personen (auch wenn es keine eigenständigen Personen gibt), Mitarbeiter, Piloten und Passagiere. Diese Aufteilung entspricht den Klassen im Objektmodell.
In Modell #2 gibt es lediglich die Tabellen Passagiere und Mitarbeiter für diese vier Entitäten. Entity Framework Core ist derzeit etwas eingeschränkt und unterstützt das Konzept Table per Type (also eine eigenständige Tabelle für jede Klasse) nicht. Daher umfasst die Tabelle Passagiere auch alle Eigenschaften von Person. Die Tabelle Mitarbeiter umfasst neben den Personeneigenschaften die Eigenschaften der Entitäten Mitarbeiter und Pilot. In der Tabelle wird per Diskriminatorspalte unterschieden zwischen Datensätzen, die ein Mitarbeiter sind, und solchen, die ein Pilot sind. Entity Framework Core mischt hier die Konzepte Table per Concrete Type (TPC) und Table per Hierarchy (TPH). Einen dezidierten Einfluss auf diese Abbildung hat man in Entity Framework Core 1.x/2.0 noch nicht. Das klassische Entity Framework bietet hier mehr Optionen.
Abhängigkeitsarten sind hier:
Ein Flug muss einen Piloten besitzen. Der Copilot ist optional.
Ein Flug kann optional einen Flugzeutyp zugeordnet haben.
Jede Person und damit auch jeder Pilot und Passagier muss ein Persondetail-Objekt besitzen.
In diesem Buch kommen beide Datenmodelle vor, teilweise auch in modifizierter Form, um bestimmte Szenarien (z. B. Datenbankschemamigrationen) aufzuzeigen.
Bitte beachten Sie, dass die Objektmodelle, die in diesem Buch zu den Datenmodellen erstellt werden, nicht das Idealbild eines Objektmodells darstellen können, denn Entity Framework Core unterstützt einige Mapping-Möglichkeiten wie z. B. das N:M-Mapping noch nicht. Das Objektmodell zum einfachen Datenmodell ist das automatisch von Entity Framework Core aus der Datenbank generierte Objektmodell (Reverse Engineering); es ist bewusst nicht verändert worden.
Bild 1.2 World Wide Wings-Datenmodell in der einfacheren Version
Bild 1.3 Objektmodell zum World Wide Wings-Datenmodell in der einfacheren Version
Bild 1.4 World Wide Wings-Datenmodell in der komplexeren Version
Bild 1.5 Objektmodell zum World Wide Wings-Datenmodell in der komplexeren Version
1.3 | Anwendungsarten in diesem Buch |
In diesem Buch erfolgen Bildschirmausgaben meist an der textbasierten Konsole in Konsolenanwendungen, denn dies ermöglicht die Fokussierung auf den Datenbankzugriff. Beim Einsatz von grafischen Benutzeroberflächen wie WPF, Windows Forms, ASP.NET Webforms oder ASP.NET MVC ist die Darstellung durch Datenbindung entkoppelt, das heißt man würde immer ein zweites Listing brauchen, um zu verstehen, dass die Datenzugriffe überhaupt liefern. Eingaben des Benutzers werden in den Konsolenbeispielen durch Variablen zu Beginn des Programmcodes simuliert.
Der Autor dieses Buchs führt seit vielen Jahren Schulungen und Beratungseinsätze im Bereich Datenzugriff durch und hat dabei die Erfahrung gemacht, dass Konsolenausgaben das didaktisch beste Instrument sind, da die Listings sonst sehr umfangreich und damit schlechter zu verstehen sind.
Natürlich ist die Konsolenausgabe in 99 % der Fälle der Softwareentwicklung nicht die gängige Praxis. Grafische Benutzeroberflächen sind Inhalt anderer Bücher, und die Datenbindung hat in der Regel keinen Einfluss auf die Form des Datenzugriffs. Dort, wo der Datenzugriff doch relevant ist, wird dieses Buch auch Datenbindungsbeispiele zeigen.
1.4 | Hilfsroutinen zur Konsolenausgabe |
Für die Bildschirmausgabe an der Konsole wird an mehreren Stellen nicht nur Console.WriteLine() verwendet, sondern auch Hilfsroutinen kommen zur Anwendung, die farbige Bildschirmausgaben erzeugen. Diese Hilfsroutinen in der Klasse CUI aus der ITV_DemoUtil.dll sind hier zum besseren Verständnis abgedruckt:
Listing 1.1 Klasse CUI mit Hilfsroutinen für die Bildschirmausgabe an der Konsole
using System; using System.Runtime.InteropServices; using System.Web; using ITVisions.UI; using System.Diagnostics; namespace ITVisions { /// <summary> /// Hilfsroutinen für Konsolen-UIs /// (C) Dr. Holger Schwichtenberg 2002-2017 /// </summary> public static class CUI { public static bool IsDebug = false; public static bool IsVerbose = false; #region Ausgaben unter bestimmten Bedingungen /// <summary> /// Ausgabe an Console, Trace und Datei - nur wenn Anwendung im DEBUG-Modus /// </summary> public static void PrintDebug(object s) { PrintDebug(s, System.Console.ForegroundColor); } /// <summary> /// Ausgabe an Console, Trace und Datei - nur wenn Anwendung im VERBOSE-Modus /// </summary> public static void PrintVerbose(object s) { PrintVerbose(s, System.Console.ForegroundColor); } #endregion #region Ausgaben mit vordefinierten Farben public static void MainHeadline(string s) { Print(s, ConsoleColor.Black, ConsoleColor.Yellow); } public static void Headline(string s) { Print(s, ConsoleColor.Yellow); } public static void HeaderFooter(string s) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(s); Console.ForegroundColor = ConsoleColor.Gray; } public static void PrintSuccess(object s) { Print(s, ConsoleColor.Green); } public static void PrintDebugSuccess(object s) { PrintDebug(s, ConsoleColor.Green); } public static void PrintVerboseSuccess(object s) { PrintVerbose(s, ConsoleColor.Green); } public static void PrintWarning(object s) { Print(s, ConsoleColor.Cyan); } public static void PrintDebugWarning(object s) { PrintDebug(s, ConsoleColor.Cyan); } public static void PrintVerboseWarning(object s) { PrintVerbose(s, ConsoleColor.Cyan); } public static void PrintError(object s) { Print(s, ConsoleColor.White, ConsoleColor.Red); } public static void PrintDebugError(object s) { PrintDebug(s, ConsoleColor.White, ConsoleColor.Red); } public static void PrintVerboseError(object s) { Print(s, ConsoleColor.White, ConsoleColor.Red); } public static void Print(object s) { PrintInternal(s, null); } #endregion #region Ausgaben mit wählbarer Farbe /// <summary> /// Ausgabe an Console, Trace und Datei - nur wenn Anwendung im DEBUG Modus /// </summary> public static void Print(object s, ConsoleColor farbe, ConsoleColor? hintergrundfarbe = null) { PrintInternal(s, farbe, hintergrundfarbe); } public static void PrintDebug(object s, ConsoleColor farbe, ConsoleColor? hintergrundfarbe = null) { if (IsDebug ∥ IsVerbose) PrintDebugOrVerbose(s, farbe, hintergrundfarbe); } public static void PrintVerbose(object s, ConsoleColor farbe) { if (!IsVerbose) return; PrintDebugOrVerbose(s, farbe); } #endregion #region Spezielle Ausgabe mit Zusatzdaten /// <summary> /// Ausgabe mit Thread-ID /// </summary> public static void PrintWithThreadID(string s, ConsoleColor c = ConsoleColor.White) { var ausgabe = String.Format("Thread #{0:00} {1:}: {2}", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToLongTimeString(), s); CUI.Print(ausgabe, c); } /// <summary> /// Ausgabe mit Uhrzeit /// </summary> public static void PrintWithTime(object s, ConsoleColor c = ConsoleColor.White) { CUI.Print(DateTime.Now.Second + "." + DateTime.Now.Millisecond + ":" + s); } private static long count; /// <summary> /// Ausgabe mit fortlaufendem Zähler /// </summary> private static void PrintWithCounter(object s, ConsoleColor farbe, ConsoleColor? hintergrundfarbe = null) { count += 1; s = String.Format("{0:0000}: {1}", count, s); CUI.Print(s, farbe, hintergrundfarbe); } #endregion #region interne Hilfsroutinen private static void PrintDebugOrVerbose(object s, ConsoleColor farbe, ConsoleColor? hintergrundfarbe = null) { count += 1; s = String.Format("{0:0000}: {1}", count, s); Print(s, farbe, hintergrundfarbe); Debug.WriteLine(s); Trace.WriteLine(s); Trace.Flush(); } /// <summary> /// Ausgabe an Console, Trace und Datei /// </summary> /// <param name="s"></param> //[DebuggerStepThrough()] private static void PrintInternal(object s, ConsoleColor? farbe = null, ConsoleColor? hintergrundfarbe = null) { if (s == null) return; if (HttpContext.Current != null) { try { //Achtung: Keine Textausgaben in Ausgabestrom von ASP.NET Webservices und WCF-Diensten und WebAPI schreiben! if (farbe != null) { HttpContext.Current.Response.Write("<span style='color:" + farbe.Value.DrawingColor().Name + "'>"); } if (!HttpContext.Current.Request.Url.ToString().ToLower().Contains(".asmx") && !HttpContext.Current.Request.Url.ToString().ToLower().Contains(".svc") && !HttpContext.Current.Request.Url.ToString().ToLower().Contains("/api/")) HttpContext.Current.Response.Write(s.ToString() + "<br>"); if (farbe != null) { HttpContext.Current.Response.Write(""); } } catch (Exception) { } } else { object x = 1; lock (x) { ConsoleColor alteFarbe = Console.ForegroundColor; ConsoleColor alteHFarbe = Console.BackgroundColor; if (farbe != null) Console.ForegroundColor = farbe.Value; if (hintergrundfarbe != null) Console.BackgroundColor = hintergrundfarbe.Value; //if (farbe.ToString().Contains("Dark")) Console.BackgroundColor = ConsoleColor.White; //else Console.BackgroundColor = ConsoleColor.Black; Console.WriteLine(s); Console.ForegroundColor = alteFarbe; Console.BackgroundColor = alteHFarbe; } } } #endregion #region Position des Konsolenfensters setzen [DllImport("kernel32.dll", ExactSpelling = true)] private static extern IntPtr GetConsoleWindow(); private static IntPtr MyConsole = GetConsoleWindow(); [DllImport("user32.dll", EntryPoint = "SetWindowPos")] public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags); // Setze Position des Konsolenfensters ohne Größe public static void SetConsolePos(int xpos, int ypos) { const int SWP_NOSIZE = 0x0001; SetWindowPos(MyConsole, 0, xpos, ypos, 0, 0, SWP_NOSIZE); } // Setze Position des Konsolenfensters mit Größe public static void SetConsolePos(int xpos, int ypos, int w, int h) { SetWindowPos(MyConsole, 0, xpos, ypos, w, h, 0); } #endregion } }
1.5 | Programmcodebeispiel zum Download |
Die Beispiele zu diesem Buch können Sie als Visual Studio-Projekte herunterladen auf der Leser-Website unter www.IT-Visions.de/Leser. Dort müssen Sie sich einmalig registrieren. Bei der Registrierung wird ein Losungswort abgefragt, das Sie als Käufer dieses Buchs ausweist. Bitte geben Sie dort Ascension ein. Durch die Registrierung erhalten Sie ein persönliches Kennwort per E-Mail zugesendet, das Sie dann für die Anmeldung nutzen können.
Bitte beachten Sie, dass nicht jede einzelne Zeile Programmcode, die Sie in diesem Buch finden, in den herunterladbaren Projekten enthalten sein kann. Die Projekte bilden funktionierende Lösungen. In diesem Buch warden auch alternative Lösungen für Einzelfälle diskutiert, die nicht unbedingt zu einer Gesamtlösung passen.
2 | Was ist Entity Framework Core? |