Entity Framework
Kod Pierwsze dane Adnotacje
Szukaj…
Uwagi
Entity Framework Code-First zapewnia zestaw atrybutów DataAnnotation, które można zastosować do klas i właściwości domeny. Atrybuty DataAnnotation zastępują domyślne konwencje Code-First.
- System.ComponentModel.DataAnnotations zawiera atrybuty wpływające na dopuszczalność nullab lub rozmiar kolumny.
- Przestrzeń nazw System.ComponentModel.DataAnnotations.Schema zawiera atrybuty wpływające na schemat bazy danych.
Uwaga: DataAnnotations daje tylko podzbiór opcji konfiguracji. Płynny interfejs API zapewnia pełny zestaw opcji konfiguracji dostępnych w programie Code-First.
Atrybut [klucz]
Klucz to pole w tabeli, które jednoznacznie identyfikuje każdy wiersz / rekord w tabeli bazy danych.
Użyj tego atrybutu, aby zastąpić domyślną konwencję Code-First . Jeśli zastosowana do właściwości, będzie używana jako kolumna klucza podstawowego dla tej klasy.
using System.ComponentModel.DataAnnotations;
public class Person
{
[Key]
public int PersonKey { get; set; } // <- will be used as primary key
public string PersonName { get; set; }
}
Jeśli wymagany jest złożony klucz podstawowy, atrybut [Klucz] można również dodać do wielu właściwości. Kolejność kolumn w kluczu złożonym należy podać w formie [ Klucz, kolumna (Kolejność = x)] .
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; }
}
Bez atrybutu [Key] EntityFramework powróci do domyślnej konwencji polegającej na użyciu właściwości klasy jako klucza podstawowego o nazwie „Id” lub „{ClassName} Id”.
public class Person
{
public int PersonID { get; set; } // <- will be used as primary key
public string PersonName { get; set; }
}
[Wymagany] atrybut
Po zastosowaniu do właściwości klasy domeny baza danych utworzy kolumnę NOT NULL.
using System.ComponentModel.DataAnnotations;
public class Person
{
public int PersonID { get; set; }
[Required]
public string PersonName { get; set; }
}
Powstała kolumna z ograniczeniem NOT NULL:
Uwaga: Może być również używany z asp.net-mvc jako atrybut sprawdzania poprawności.
Atrybuty [MaxLength] i [MinLength]
Atrybut [MaxLength (int)] można zastosować do właściwości typu ciągu lub tablicy klasy domeny. Entity Framework ustawi rozmiar kolumny na określoną wartość.
using System.ComponentModel.DataAnnotations;
public class Person
{
public int PersonID { get; set; }
[MinLength(3), MaxLength(100)]
public string PersonName { get; set; }
}
Powstała kolumna o określonej długości kolumny:
Atrybut [MinLength (int)] jest atrybutem sprawdzania poprawności, nie wpływa na strukturę bazy danych. Jeśli spróbujemy wstawić / zaktualizować osobę o nazwie PersonName o długości mniejszej niż 3 znaki, zatwierdzenie to nie powiedzie się. Otrzymamy DbUpdateConcurrencyException
, który będziemy musieli obsłużyć.
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'."
}
}
Zarówno atrybuty [MaxLength], jak i [MinLength] mogą być również używane z asp.net-mvc jako atrybut sprawdzania poprawności.
Atrybut [Zakres (min., Maks.)]
Określa numeryczny minimalny i maksymalny zakres właściwości
using System.ComponentModel.DataAnnotations;
public partial class Enrollment
{
public int EnrollmentID { get; set; }
[Range(0, 4)]
public Nullable<decimal> Grade { get; set; }
}
Jeśli spróbujemy wstawić / zaktualizować ocenę o wartości spoza zakresu, zatwierdzenie to nie powiedzie się. Otrzymamy DbUpdateConcurrencyException
, który będziemy musieli obsłużyć.
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
}
}
Może być również używany z asp.net-mvc jako atrybut sprawdzania poprawności.
Wynik:
Atrybut [DatabaseGenerated]
Określa sposób, w jaki baza danych generuje wartości właściwości. Istnieją trzy możliwe wartości:
-
None
określa, że wartości nie są generowane przez bazę danych. -
Identity
określa, że kolumna jest kolumną tożsamości , która jest zwykle używana w przypadku liczb całkowitych kluczy podstawowych. -
Computed
określa, że baza danych generuje wartość dla kolumny.
Jeśli wartość jest inna niż None
, Entity Framework nie zatwierdzi zmian dokonanych we właściwości z powrotem do bazy danych.
Domyślnie (na podstawie StoreGeneratedIdentityKeyConvention
) właściwość klucza liczby całkowitej będzie traktowana jako kolumna tożsamości. Aby zastąpić tę konwencję i zmusić ją do traktowania jej jako kolumny niebędącej tożsamością, możesz użyć atrybutu DatabaseGenerated
o wartości 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
}
Poniższy kod SQL tworzy tabelę z obliczoną kolumną:
CREATE TABLE [Person] (
Name varchar(100) PRIMARY KEY,
DateOfBirth Date NOT NULL,
Age AS DATEDIFF(year, DateOfBirth, GETDATE())
)
GO
Aby utworzyć encję do reprezentowania rekordów w powyższej tabeli, należy użyć atrybutu DatabaseGenerated
o wartości 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; }
}
Atrybut [NotMapped]
Zgodnie z konwencją Code-First Entity Framework tworzy kolumnę dla każdej właściwości publicznej, która ma obsługiwany typ danych i ma zarówno getter, jak i setter. Adnotację [NotMapped] należy zastosować do wszystkich właściwości, dla których NIE chcemy kolumny w tabeli bazy danych.
Przykładem właściwości, której nie chcielibyśmy przechowywać w bazie danych, jest pełne imię i nazwisko ucznia oparte na jego imieniu i nazwisku. Można to obliczyć w locie i nie ma potrzeby przechowywania go w bazie danych.
public string FullName => string.Format("{0} {1}", FirstName, LastName);
Właściwość „FullName” ma tylko moduł pobierający i nie ustawiający, więc domyślnie Entity Framework NIE utworzy dla niego kolumny.
Innym przykładem właściwości, której nie chcielibyśmy przechowywać w bazie danych, jest „AverageGrade” studenta. Nie chcemy uzyskiwać AverageGrade na żądanie; zamiast tego możemy mieć procedurę gdzie indziej, która ją oblicza.
[NotMapped]
public float AverageGrade { set; get; }
„AverageGrade” musi być oznaczony adnotacją [NotMapped] , w przeciwnym razie Entity Framework utworzy dla niego kolumnę.
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; }
}
Dla powyższej jednostki zobaczymy wewnątrz DbMigration.cs
CreateTable(
"dbo.Students",
c => new
{
Id = c.Int(nullable: false, identity: true),
FirstName = c.String(),
LastName = c.String(),
})
.PrimaryKey(t => t.Id);
oraz w SQL Server Management Studio
Atrybut [Tabela]
[Table("People")]
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
}
Mówi Entity Framework, aby używał określonej nazwy tabeli zamiast generowania jej (tj. Person
lub Persons
)
Możemy również określić schemat dla tabeli za pomocą atrybutu [Tabela]
[Table("People", Schema = "domain")]
Atrybut [Kolumna]
public class Person
{
public int PersonID { get; set; }
[Column("NameOfPerson")]
public string PersonName { get; set; }
}
Informuje Entity Framework, aby używał określonej nazwy kolumny zamiast nazwy właściwości. Możesz także określić typ danych bazy danych i kolejność kolumn w tabeli:
[Column("NameOfPerson", TypeName = "varchar", Order = 1)]
public string PersonName { get; set; }
Atrybut [Indeks]
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
[Index]
public int Age { get; set; }
}
Tworzy indeks bazy danych dla kolumny lub zestawu kolumn.
[Index("IX_Person_Age")]
public int Age { get; set; }
Spowoduje to utworzenie indeksu o określonej nazwie.
[Index(IsUnique = true)]
public int Age { get; set; }
To tworzy unikalny indeks.
[Index("IX_Person_NameAndAge", 1)]
public int Age { get; set; }
[Index("IX_Person_NameAndAge", 2)]
public string PersonName { get; set; }
To tworzy indeks złożony przy użyciu 2 kolumn. Aby to zrobić, musisz podać tę samą nazwę indeksu i podać kolejność kolumn.
Uwaga : Atrybut indeksu został wprowadzony w Entity Framework 6.1. Jeśli używasz wcześniejszej wersji, informacje w tej sekcji nie mają zastosowania.
Atrybut [ForeignKey (string)]
Określa niestandardową nazwę klucza obcego, jeśli pożądany jest klucz obcy niezgodny z konwencją EF.
public class Person
{
public int IdAddress { get; set; }
[ForeignKey(nameof(IdAddress))]
public virtual Address HomeAddress { get; set; }
}
Można tego również użyć, gdy istnieje wiele relacji z tym samym typem jednostki.
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; }
}
Bez atrybutów ForeignKey
EF może je pomieszać i użyć wartości BillingAddressID
podczas pobierania MailingAddress
lub może po prostu wymyślić inną nazwę dla kolumny na podstawie własnych konwencji nazewnictwa (takich jak Address_MailingAddress_Id
) i spróbować użyć tego zamiast tego (co spowodowałoby błąd, jeśli używasz tego z istniejącą bazą danych).
Atrybut [StringLength (int)]
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; }
}
Definiuje maksymalną długość pola ciągu.
Uwaga : Może być również używany z asp.net-mvc jako atrybut sprawdzania poprawności.
Atrybut [Datownik]
Atrybut [TimeStamp] można zastosować tylko do jednej właściwości tablicy bajtów w danej klasie encji. Entity Framework utworzy w tabeli bazy danych niepoznawalną kolumnę datownika dla tej właściwości. Entity Framework automatycznie użyje tej kolumny znacznika czasu podczas sprawdzania współbieżności.
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] Atrybut
Ten atrybut jest stosowany do właściwości klasy. Możesz użyć atrybutu ConcurrencyCheck, jeśli chcesz użyć istniejących kolumn do sprawdzania współbieżności, a nie oddzielnej kolumny znacznika czasu dla współbieżności.
using System.ComponentModel.DataAnnotations;
public class Author
{
public int AuthorId { get; set; }
[ConcurrencyCheck]
public string AuthorName { get; set; }
}
Z powyższego przykładu atrybut ConcurrencyCheck jest stosowany do właściwości AuthorName klasy Author. Zatem Code-First uwzględni kolumnę AuthorName w poleceniu update (gdzie klauzula), aby sprawdzić optymistyczną współbieżność.
Atrybut [InverseProperty (string)]
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 można wykorzystać do identyfikacji relacji dwukierunkowych, gdy istnieje wiele relacji dwukierunkowych między dwoma jednostkami.
Mówi Entity Framework, które właściwości nawigacji powinny pasować do właściwości po drugiej stronie.
Entity Framework nie wie, która mapa właściwości nawigacji, z którymi właściwościami po drugiej stronie, gdy istnieje wiele relacji dwukierunkowych między dwoma podmiotami.
Potrzebuje nazwy odpowiedniej właściwości nawigacji w powiązanej klasie jako parametru.
Można to również wykorzystać w przypadku jednostek, które są powiązane z innymi jednostkami tego samego typu, tworząc relację rekurencyjną.
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; }
}
Zwróć także uwagę na użycie atrybutu ForeignKey
do określenia kolumny używanej dla klucza obcego w tabeli. W pierwszym przykładzie dwie właściwości klasy Employee
mogły mieć zastosowany atrybut ForeignKey
celu zdefiniowania nazw kolumn.
Atrybut [ComplexType]
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; }
}
Oznacz klasę jako typ złożony w Entity Framework.
Typy złożone (lub obiekty wartości w projektach opartych na domenie) nie mogą być śledzone same, ale są śledzone jako część encji. Właśnie dlatego BlogDetails w tym przykładzie nie ma właściwości klucza.
Mogą być przydatne podczas opisywania jednostek domeny w wielu klasach i dzielenia tych klas na kompletne jednostki.