Entity Framework
Erste Datenanmerkungen kodieren
Suche…
Bemerkungen
Entity Framework Code-First stellt eine Reihe von DataAnnotation-Attributen bereit, die Sie auf Ihre Domänenklassen und -eigenschaften anwenden können. DataAnnotation-Attribute überschreiben die Standard-Code-First-Konventionen.
- System.ComponentModel.DataAnnotations enthält Attribute, die sich auf die Nullfähigkeit oder die Größe der Spalte auswirken.
- Der Namespace System.ComponentModel.DataAnnotations.Schema enthält Attribute, die sich auf das Schema der Datenbank auswirken.
Hinweis: Mit DataAnnotations erhalten Sie nur einen Teil der Konfigurationsoptionen. Fluent API bietet einen vollständigen Satz von Konfigurationsoptionen, die in Code-First verfügbar sind.
[Schlüssel] -Attribut
Schlüssel ist ein Feld in einer Tabelle, das jede Zeile / jeden Datensatz in einer Datenbanktabelle eindeutig identifiziert.
Verwenden Sie dieses Attribut, um die Standard-Code-First-Konvention zu überschreiben . Wenn sie auf eine Eigenschaft angewendet werden, wird sie als Primärschlüsselspalte für diese Klasse verwendet.
using System.ComponentModel.DataAnnotations;
public class Person
{
[Key]
public int PersonKey { get; set; } // <- will be used as primary key
public string PersonName { get; set; }
}
Wenn ein zusammengesetzter Primärschlüssel erforderlich ist, kann das Attribut [Schlüssel] auch mehreren Eigenschaften hinzugefügt werden. Die Reihenfolge der Spalten innerhalb des zusammengesetzten Schlüssels muss in der Form [ Schlüssel, Spalte (Reihenfolge = x)] angegeben werden .
using System.ComponentModel.DataAnnotations;
public class Person
{
[Key, Column(Order = 0)]
public int PersonKey1 { get; set; } // <- will be used as part of the primary key
[Key, Column(Order = 1)]
public int PersonKey2 { get; set; } // <- will be used as part of the primary key
public string PersonName { get; set; }
}
Ohne das Attribut [Key] greift EntityFramework auf die Standardkonvention zurück, bei der die Eigenschaft der Klasse als Primärschlüssel mit dem Namen "Id" oder "{ClassName} Id" verwendet wird.
public class Person
{
public int PersonID { get; set; } // <- will be used as primary key
public string PersonName { get; set; }
}
[Erforderlich] Attribut
Bei der Anwendung auf eine Eigenschaft einer Domänenklasse erstellt die Datenbank eine NOT NULL-Spalte.
using System.ComponentModel.DataAnnotations;
public class Person
{
public int PersonID { get; set; }
[Required]
public string PersonName { get; set; }
}
Die resultierende Spalte mit der NOT NULL-Einschränkung:
Hinweis: Es kann auch mit asp.net-mvc als Validierungsattribut verwendet werden.
Attribute [MaxLength] und [MinLength]
Das Attribut [MaxLength (int)] kann auf eine String- oder Array-Typ-Eigenschaft einer Domänenklasse angewendet werden. Entity Framework setzt die Größe einer Spalte auf den angegebenen Wert.
using System.ComponentModel.DataAnnotations;
public class Person
{
public int PersonID { get; set; }
[MinLength(3), MaxLength(100)]
public string PersonName { get; set; }
}
Die resultierende Spalte mit der angegebenen Spaltenlänge:
Das Attribut [MinLength (int)] ist ein Validierungsattribut. Es hat keinen Einfluss auf die Datenbankstruktur. Wenn wir versuchen, eine Person mit PersonName mit einer Länge von weniger als 3 Zeichen einzufügen / zu aktualisieren, schlägt diese Festschreibung fehl. Wir erhalten eine DbUpdateConcurrencyException
, die wir behandeln müssen.
using (var db = new ApplicationDbContext())
{
db.Staff.Add(new Person() { PersonName = "ng" });
try
{
db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
//ErrorMessage = "The field PersonName must be a string or array type with a minimum length of '3'."
}
}
Beide Attribute [MaxLength] und [MinLength] können auch mit asp.net-mvc als Validierungsattribut verwendet werden.
Attribut [Bereich (min, max)]
Gibt einen numerischen Minimal- und Maximalbereich für eine Eigenschaft an
using System.ComponentModel.DataAnnotations;
public partial class Enrollment
{
public int EnrollmentID { get; set; }
[Range(0, 4)]
public Nullable<decimal> Grade { get; set; }
}
Wenn wir versuchen, eine Note mit einem Wert außerhalb des Bereichs einzufügen / zu aktualisieren, schlägt diese Festschreibung fehl. Wir erhalten eine DbUpdateConcurrencyException
, die wir behandeln müssen.
using (var db = new ApplicationDbContext())
{
db.Enrollments.Add(new Enrollment() { Grade = 1000 });
try
{
db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
// Validation failed for one or more entities
}
}
Es kann auch mit asp.net-mvc als Validierungsattribut verwendet werden.
Ergebnis:
[DatabaseGenerated] -Attribut
Gibt an, wie die Datenbank Werte für die Eigenschaft generiert. Es gibt drei mögliche Werte:
-
None
gibt an, dass die Werte nicht von der Datenbank generiert werden. -
Identity
gibt an, dass die Spalte eine Identitätsspalte ist , die normalerweise für Ganzzahl-Primärschlüssel verwendet wird. -
Computed
gibt an, dass die Datenbank den Wert für die Spalte generiert.
Wenn der Wert nicht " None
, werden die an der Eigenschaft vorgenommenen Änderungen nicht in die Datenbank zurückgegeben.
Standardmäßig (basierend auf StoreGeneratedIdentityKeyConvention
) wird eine Integer-Schlüsseleigenschaft als Identitätsspalte behandelt. Um diese Konvention zu überschreiben und zu erzwingen, dass sie als Nicht-Identitätsspalte behandelt wird, können Sie das DatabaseGenerated
Attribut mit dem Wert None
.
using System.ComponentModel.DataAnnotations.Schema;
public class Foo
{
[Key]
public int Id { get; set; } // identity (auto-increment) column
}
public class Bar
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; } // non-identity column
}
Die folgende SQL erstellt eine Tabelle mit einer berechneten Spalte:
CREATE TABLE [Person] (
Name varchar(100) PRIMARY KEY,
DateOfBirth Date NOT NULL,
Age AS DATEDIFF(year, DateOfBirth, GETDATE())
)
GO
Um eine Entität für die Darstellung der Datensätze in der obigen Tabelle zu erstellen, müssen Sie das DatabaseGenerated
Attribut mit dem Wert Computed
.
[Table("Person")]
public class Person
{
[Key, StringLength(100)]
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int Age { get; set; }
}
[NotMapped] -Attribut
Nach der Code-First-Konvention erstellt Entity Framework eine Spalte für jede öffentliche Eigenschaft, die einen unterstützten Datentyp hat und sowohl einen Getter als auch einen Setter enthält. Die Annotation [NotMapped] muss auf alle Eigenschaften angewendet werden, für die KEINE Spalte in einer Datenbanktabelle gewünscht wird.
Ein Beispiel für eine Eigenschaft, die wir möglicherweise nicht in der Datenbank speichern möchten, ist der vollständige Name eines Schülers, der auf seinem Vor- und Nachnamen basiert. Das kann man sofort berechnen und muss nicht in der Datenbank gespeichert werden.
public string FullName => string.Format("{0} {1}", FirstName, LastName);
Die Eigenschaft "FullName" hat nur einen Getter und keinen Setter. Daher erstellt Entity Framework standardmäßig KEINE Spalte dafür.
Ein anderes Beispiel für eine Eigenschaft, die wir möglicherweise nicht in der Datenbank speichern möchten, ist das "AverageGrade" eines Schülers. Wir möchten den AverageGrade nicht auf Abruf erhalten. Stattdessen könnten wir an anderer Stelle eine Routine haben, die sie berechnet.
[NotMapped]
public float AverageGrade { set; get; }
"AverageGrade" muss mit [NotMapped] gekennzeichnet sein , andernfalls erstellt Entity Framework eine Spalte dafür.
using System.ComponentModel.DataAnnotations.Schema;
public class Student
{
public int Id { set; get; }
public string FirstName { set; get; }
public string LastName { set; get; }
public string FullName => string.Format("{0} {1}", FirstName, LastName);
[NotMapped]
public float AverageGrade { set; get; }
}
Für die obige Entität sehen wir DbMigration.cs
CreateTable(
"dbo.Students",
c => new
{
Id = c.Int(nullable: false, identity: true),
FirstName = c.String(),
LastName = c.String(),
})
.PrimaryKey(t => t.Id);
und in SQL Server Management Studio
[Tabelle] -Attribut
[Table("People")]
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
}
Weist Entity Framework an, einen bestimmten Tabellennamen zu verwenden, anstatt einen zu generieren (zB Person
oder Persons
)
Wir können auch ein Schema für die Tabelle mit dem Attribut [Tabelle] angeben
[Table("People", Schema = "domain")]
[Spalte] -Attribut
public class Person
{
public int PersonID { get; set; }
[Column("NameOfPerson")]
public string PersonName { get; set; }
}
Weist Entity Framework an, einen bestimmten Spaltennamen zu verwenden, anstatt den Namen der Eigenschaft zu verwenden. Sie können auch den Datenbankdatentyp und die Reihenfolge der Spalte in der Tabelle angeben:
[Column("NameOfPerson", TypeName = "varchar", Order = 1)]
public string PersonName { get; set; }
[Index] -Attribut
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
[Index]
public int Age { get; set; }
}
Erstellt einen Datenbankindex für eine Spalte oder einen Satz von Spalten.
[Index("IX_Person_Age")]
public int Age { get; set; }
Dadurch wird ein Index mit einem bestimmten Namen erstellt.
[Index(IsUnique = true)]
public int Age { get; set; }
Dadurch wird ein eindeutiger Index erstellt.
[Index("IX_Person_NameAndAge", 1)]
public int Age { get; set; }
[Index("IX_Person_NameAndAge", 2)]
public string PersonName { get; set; }
Dadurch wird ein zusammengesetzter Index mit zwei Spalten erstellt. Dazu müssen Sie denselben Indexnamen angeben und eine Spaltenreihenfolge angeben.
Hinweis : Das Index-Attribut wurde in Entity Framework 6.1 eingeführt. Wenn Sie eine frühere Version verwenden, gelten die Informationen in diesem Abschnitt nicht.
[ForeignKey (Zeichenfolge)] Attribut
Gibt den benutzerdefinierten Fremdschlüsselnamen an, wenn ein Fremdschlüssel gewünscht wird, der nicht der Konvention von EF entspricht.
public class Person
{
public int IdAddress { get; set; }
[ForeignKey(nameof(IdAddress))]
public virtual Address HomeAddress { get; set; }
}
Dies kann auch verwendet werden, wenn Sie mehrere Beziehungen zu demselben Entitätstyp haben.
using System.ComponentModel.DataAnnotations.Schema;
public class Customer
{
...
public int MailingAddressID { get; set; }
public int BillingAddressID { get; set; }
[ForeignKey("MailingAddressID")]
public virtual Address MailingAddress { get; set; }
[ForeignKey("BillingAddressID")]
public virtual Address BillingAddress { get; set; }
}
Ohne die ForeignKey
Attribute könnte EF sie BillingAddressID
beim Abrufen der MailingAddress
den Wert von BillingAddressID
MailingAddress
, oder es wird nur ein anderer Name für die Spalte MailingAddress
, der auf seinen eigenen Namenskonventionen (wie Address_MailingAddress_Id
) basiert Stattdessen (was zu einem Fehler führen würde, wenn Sie dies mit einer vorhandenen Datenbank verwenden).
[StringLength (int)] Attribut
using System.ComponentModel.DataAnnotations;
public class Post
{
public int Id { get; set; }
[StringLength(100)]
public string Title { get; set;}
[StringLength(300)]
public string Abstract { get; set; }
public string Description { get; set; }
}
Definiert eine maximale Länge für ein Zeichenfolgefeld.
Hinweis : Es kann auch mit asp.net-mvc als Validierungsattribut verwendet werden.
[Zeitstempel] -Attribut
Das Attribut [TimeStamp] kann nur auf eine Byte-Array-Eigenschaft in einer bestimmten Entitätsklasse angewendet werden. Entity Framework erstellt für diese Eigenschaft eine nicht-nullfähige Zeitstempelpalte in der Datenbanktabelle. Entity Framework verwendet diese TimeStamp-Spalte automatisch für die Parallelitätsprüfung.
using System.ComponentModel.DataAnnotations.Schema;
public class Student
{
public int Id { set; get; }
public string FirstName { set; get; }
public string LastName { set; get; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
[ConcurrencyCheck] Attribut
Dieses Attribut wird auf die Klasseneigenschaft angewendet. Sie können das ConcurrencyCheck-Attribut verwenden, wenn Sie vorhandene Spalten für die Parallelitätsprüfung und keine separate Zeitstempelpalte für die Parallelität verwenden möchten.
using System.ComponentModel.DataAnnotations;
public class Author
{
public int AuthorId { get; set; }
[ConcurrencyCheck]
public string AuthorName { get; set; }
}
Im obigen Beispiel wird das ConcurrencyCheck-Attribut auf die AuthorName-Eigenschaft der Author-Klasse angewendet. Daher enthält Code-First die Spalte AuthorName im Aktualisierungsbefehl (where-Klausel), um die optimistische Parallelität zu überprüfen.
Attribut [InverseProperty (Zeichenfolge)]
using System.ComponentModel.DataAnnotations.Schema;
public class Department
{
...
public virtual ICollection<Employee> PrimaryEmployees { get; set; }
public virtual ICollection<Employee> SecondaryEmployees { get; set; }
}
public class Employee
{
...
[InverseProperty("PrimaryEmployees")]
public virtual Department PrimaryDepartment { get; set; }
[InverseProperty("SecondaryEmployees")]
public virtual Department SecondaryDepartment { get; set; }
}
InverseProperty kann verwendet werden, um Zweiwege- Beziehungen zu identifizieren , wenn zwischen zwei Entitäten mehrere Zweiwege- Beziehungen bestehen.
Sie teilt Entity Framework mit, welche Navigationseigenschaften mit den Eigenschaften auf der anderen Seite übereinstimmen sollten.
Entity Framework weiß nicht, welche Navigationseigenschaftskarte mit welchen Eigenschaften auf der anderen Seite verbunden ist, wenn zwischen zwei Entitäten mehrere bidirektionale Beziehungen bestehen.
Es benötigt den Namen der entsprechenden Navigationseigenschaft in der zugehörigen Klasse als Parameter.
Dies kann auch für Entitäten verwendet werden, die eine Beziehung zu anderen Entitäten desselben Typs haben und eine rekursive Beziehung bilden.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class TreeNode
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
...
[ForeignKey("ParentID")]
public TreeNode ParentNode { get; set; }
[InverseProperty("ParentNode")]
public virtual ICollection<TreeNode> ChildNodes { get; set; }
}
Beachten Sie auch die Verwendung des ForeignKey
Attributs, um die Spalte anzugeben, die für den Fremdschlüssel in der Tabelle verwendet wird. Im ersten Beispiel wurde ForeignKey
für die beiden Eigenschaften der Employee
Klasse das ForeignKey
Attribut angewendet, um die Spaltennamen zu definieren.
[ComplexType] -Attribut
using System.ComponentModel.DataAnnotations.Schema;
[ComplexType]
public class BlogDetails
{
public DateTime? DateCreated { get; set; }
[MaxLength(250)]
public string Description { get; set; }
}
public class Blog
{
...
public BlogDetails BlogDetail { get; set; }
}
Markieren Sie die Klasse als komplexen Typ in Entity Framework.
Komplexe Typen (oder Wertobjekte im domänengesteuerten Design) können nicht alleine verfolgt werden, sie werden jedoch als Teil einer Entität verfolgt. Aus diesem Grund verfügt BlogDetails im Beispiel über keine Schlüsseleigenschaft.
Sie können nützlich sein, wenn Sie Domänenentitäten über mehrere Klassen hinweg beschreiben und diese Klassen zu einer vollständigen Entität zusammenfassen.