Entity Framework - Erstes Beispiel
Definieren wir ein sehr einfaches Modell mithilfe von Klassen. Wir definieren sie nur in der Datei Program.cs, aber in einer realen Anwendung teilen Sie Ihre Klassen in separate Dateien und möglicherweise in ein separates Projekt auf. Im Folgenden finden Sie ein Datenmodell, das wir mit dem Code First-Ansatz erstellen werden.
Modell erstellen
Fügen Sie die folgenden drei Klassen in der Datei Program.cs hinzu, indem Sie den folgenden Code für die Schülerklasse verwenden.
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Die ID-Eigenschaft wird zur Primärschlüsselspalte der Datenbanktabelle, die dieser Klasse entspricht.
Die Enrollments-Eigenschaft ist eine Navigationseigenschaft. Navigationseigenschaften enthalten andere Entitäten, die mit dieser Entität verknüpft sind.
In diesem Fall enthält die Enrollments-Eigenschaft einer Student-Entität alle Enrollment-Entitäten, die sich auf diese Student-Entität beziehen.
Navigationseigenschaften werden normalerweise als virtuell definiert, damit sie bestimmte Entity Framework-Funktionen wie z. B. verzögertes Laden nutzen können.
Wenn eine Navigationseigenschaft mehrere Entitäten enthalten kann (wie in Viele-zu-Viele- oder Eins-zu-Viele-Beziehungen), muss ihr Typ eine Liste sein, in der Einträge hinzugefügt, gelöscht und aktualisiert werden können, z. B. ICollection.
Es folgt die Implementierung für die Kursklasse.
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Die Enrollments-Eigenschaft ist eine Navigationseigenschaft. Eine Kursentität kann mit einer beliebigen Anzahl von Registrierungsentitäten verknüpft werden.
Es folgt die Implementierung für die Registrierungsklasse und die Aufzählung.
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
Die EnrollmentID-Eigenschaft ist der Primärschlüssel.
Die Grade-Eigenschaft ist eine Aufzählung. Das Fragezeichen nach der Grade-Typdeklaration zeigt an, dass die Grade-Eigenschaft nullwertfähig ist.
Eine Note, die null ist, unterscheidet sich von einer Note null. Null bedeutet, dass eine Note nicht bekannt ist oder noch nicht vergeben wurde.
Die Eigenschaften StudentID und CourseID sind Fremdschlüssel, und die entsprechenden Navigationseigenschaften sind Student und Course.
Eine Registrierungsentität ist einer Schüler- und einer Kursentität zugeordnet, sodass die Eigenschaft nur eine einzelne Schüler- und Kursentität enthalten kann.
Datenbankkontext erstellen
Die Hauptklasse, die die Entity Framework-Funktionalität für ein bestimmtes Datenmodell koordiniert, ist die Datenbankkontextklasse, mit der Daten abgefragt und gespeichert werden können. Sie können diese Klasse erstellen, indem Sie sie von der DbContext-Klasse ableiten und ein typisiertes DbSet verfügbar machen
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
Im Folgenden finden Sie den vollständigen Code in der Datei Program.cs.
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFCodeFirstDemo {
class Program {
static void Main(string[] args) {}
}
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
}
Der obige Code ist alles, was wir brauchen, um Daten zu speichern und abzurufen. Fügen wir einige Daten hinzu und rufen sie dann ab. Es folgt der Code in der Hauptmethode.
static void Main(string[] args) {
using (var context = new MyContext()) {
// Create and save a new Students
Console.WriteLine("Adding new students");
var student = new Student {
FirstMidName = "Alain", LastName = "Bomer",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student);
var student1 = new Student {
FirstMidName = "Mark", LastName = "Upston",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student1);
context.SaveChanges();
// Display all Students from the database
var students = (from s in context.Students
orderby s.FirstMidName select s).ToList<Student>();
Console.WriteLine("Retrieve all Students from the database:");
foreach (var stdnt in students) {
string name = stdnt.FirstMidName + " " + stdnt.LastName;
Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
Wenn der obige Code ausgeführt wird, erhalten Sie die folgende Ausgabe.
Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...
Nun stellt sich die Frage, wo sich die Daten und die Datenbank befinden, in denen wir einige Daten hinzugefügt und dann aus der Datenbank abgerufen haben. Konventionell hat DbContext eine Datenbank für Sie erstellt.
Wenn eine lokale SQL Express-Instanz verfügbar ist, hat Code First die Datenbank auf dieser Instanz erstellt.
Wenn SQL Express nicht verfügbar ist, versucht Code First, LocalDb zu verwenden.
Die Datenbank ist nach dem vollständig qualifizierten Namen des abgeleiteten Kontexts benannt.
In unserem Fall ist eine SQL Express-Instanz verfügbar und der Datenbankname lautet EFCodeFirstDemo.MyContext (siehe folgende Abbildung).
Dies sind nur die Standardkonventionen, und es gibt verschiedene Möglichkeiten, die von Code First verwendete Datenbank zu ändern.
Wie Sie im obigen Bild sehen können, wurden Tabellen für Studenten, Kurse und Einschreibungen erstellt, und jede Tabelle enthält Spalten mit dem entsprechenden Datentyp und der entsprechenden Länge.
Die Spaltennamen und der Datentyp stimmen auch mit den Eigenschaften der jeweiligen Domänenklassen überein.
Datenbankinitialisierung
Im obigen Beispiel haben wir gesehen, dass Code First automatisch eine Datenbank erstellt. Wenn Sie jedoch den Namen der Datenbank und des Servers ändern möchten, lassen Sie uns sehen, wie Code First den Datenbanknamen und den Server beim Initialisieren einer Datenbank festlegt. Schauen Sie sich das folgende Diagramm an.
Sie können den Basiskonstruktor der Kontextklasse folgendermaßen definieren.
- Kein Parameter
- Name der Datenbank
- Name der Verbindungszeichenfolge
Kein Parameter
Wenn Sie den Basiskonstruktor der Kontextklasse ohne Parameter angeben, wie im obigen Beispiel gezeigt, erstellt das Entitätsframework eine Datenbank auf Ihrem lokalen SQLEXPRESS-Server mit dem Namen {Namespace}. {Name der Kontextklasse}.
Im obigen Beispiel hat die automatisch erstellte Datenbank den Namen EFCodeFirstDemo.MyContext. Wenn Sie sich den Namen ansehen, werden Sie feststellen, dass EFCodeFirstDemo der Namespace und MyContext der Name der Kontextklasse ist, wie im folgenden Code gezeigt.
public class MyContext : DbContext {
public MyContext() : base() {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
Name der Datenbank
Wenn Sie den Datenbanknamen als Parameter in einem Basiskonstruktor der Kontextklasse übergeben, erstellt Code First automatisch erneut eine Datenbank. Diesmal wird der Name jedoch als Parameter im Basiskonstruktor auf dem lokalen SQLEXPRESS-Datenbankserver übergeben .
Im folgenden Code wird MyContextDB als Parameter im Basiskonstruktor angegeben. Wenn Sie Ihre Anwendung ausführen, wird die Datenbank mit dem Namen MyContextDB auf Ihrem lokalen SQL Server erstellt.
public class MyContext : DbContext {
public MyContext() : base("MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
Name der Verbindungszeichenfolge
Dies ist eine einfache Möglichkeit, DbContext anzuweisen, einen anderen Datenbankserver als SQL Express oder LocalDb zu verwenden. Sie können eine Verbindungszeichenfolge in Ihre Datei app.config einfügen.
Wenn der Name der Verbindungszeichenfolge mit dem Namen Ihres Kontexts übereinstimmt (entweder mit oder ohne Namespace-Qualifikation), wird er von DbContext gefunden, wenn der Konstruktor ohne Parameter verwendet wird.
Wenn sich der Name der Verbindungszeichenfolge vom Namen Ihres Kontexts unterscheidet, können Sie DbContext anweisen, diese Verbindung im Code First-Modus zu verwenden, indem Sie den Namen der Verbindungszeichenfolge an den DbContext-Konstruktor übergeben.
public class MyContext : DbContext {
public MyContext() : base("name = MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
Im obigen Code wird im Basiskonstruktor ein Ausschnitt der Verbindungszeichenfolge der Kontextklasse als Parameter angegeben.
Der Name der Verbindungszeichenfolge muss mit "name =" beginnen. Andernfalls wird er als Datenbankname betrachtet.
Dieses Formular macht deutlich, dass Sie erwarten, dass die Verbindungszeichenfolge in Ihrer Konfigurationsdatei gefunden wird. Eine Ausnahme wird ausgelöst, wenn keine Verbindungszeichenfolge mit dem angegebenen Namen gefunden wird.
<connectionStrings>
<add name = "MyContextDB"
connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true"
providerName = "System.Data.SqlClient"/>
</connectionStrings>
Der Datenbankname in der Verbindungszeichenfolge in app.config lautet EFMyContextDB. CodeFirst erstellt eine neueEFMyContextDB Datenbank oder vorhandene verwenden EFMyContextDB Datenbank am lokalen SQL Server.
Domänenklassen
Bisher haben wir EF das Modell nur anhand seiner Standardkonventionen ermitteln lassen, aber es wird Zeiten geben, in denen unsere Klassen nicht den Konventionen entsprechen und wir in der Lage sein müssen, weitere Konfigurationen durchzuführen. Sie können diese Konventionen jedoch überschreiben, indem Sie Ihre Domänenklassen so konfigurieren, dass EF die erforderlichen Informationen erhält. Es gibt zwei Möglichkeiten, um Ihre Domänenklassen zu konfigurieren:
- Datenanmerkungen
- Fließende API
Datenanmerkungen
DataAnnotations wird zum Konfigurieren Ihrer Klassen verwendet, um die am häufigsten benötigten Konfigurationen hervorzuheben. DataAnnotations werden auch von einer Reihe von .NET-Anwendungen wie ASP.NET MVC verstanden, mit denen diese Anwendungen dieselben Annotationen für clientseitige Validierungen nutzen können.
Im Folgenden sind die Datenanmerkungen aufgeführt, die in der Schülerklasse verwendet werden.
public class Enrollment {
[Key]
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
[ForeignKey("CourseID")]
public virtual Course Course { get; set; }
[ForeignKey("ID")]
public virtual Student Student { get; set; }
}
Fließende API
Die meisten Modellkonfigurationen können mit einfachen Datenanmerkungen durchgeführt werden. Die fließende API ist eine erweiterte Methode zur Angabe der Modellkonfiguration, die alle Funktionen von Datenanmerkungen abdeckt, zusätzlich zu einer erweiterten Konfiguration, die mit Datenanmerkungen nicht möglich ist. Datenanmerkungen und die fließende API können zusammen verwendet werden.
Um auf die fließende API zuzugreifen, überschreiben Sie die OnModelCreating-Methode in DbContext. Benennen Sie nun den Spaltennamen in der Schülertabelle von FirstMidName in FirstName um, wie im folgenden Code gezeigt.
public class MyContext : DbContext {
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
.HasColumnName("FirstName");
}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}