Entity Framework
Код First DataAnnotations
Поиск…
замечания
Entity Framework Code-First предоставляет набор атрибутов DataAnnotation, которые вы можете применить к своим классам и свойствам домена. Атрибуты DataAnnotation переопределяют стандартные соглашения Code-First.
- System.ComponentModel.DataAnnotations включает атрибуты, которые влияют на нулеустойчивость или размер столбца.
- System.ComponentModel.DataAnnotations.Schema namespace включает атрибуты, которые влияют на схему базы данных.
Примечание. DataAnnotations предоставляет только набор параметров конфигурации. Fluent API предоставляет полный набор параметров конфигурации, доступных в Code-First.
Атрибут [Key]
Ключ - это поле в таблице, которое однозначно идентифицирует каждую строку / запись в таблице базы данных.
Используйте этот атрибут, чтобы переопределить стандартное соглашение Code-First . Если применяется к свойству, он будет использоваться в качестве столбца первичного ключа для этого класса.
using System.ComponentModel.DataAnnotations;
public class Person
{
[Key]
public int PersonKey { get; set; } // <- will be used as primary key
public string PersonName { get; set; }
}
Если требуется составной первичный ключ, атрибут [Key] можно также добавить к нескольким свойствам. Порядок столбцов в составном ключе должен быть указан в форме [ Ключ, Столбец (Заказ = 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; }
}
Без атрибута [Key] EntityFramework вернется к соглашению по умолчанию, которое должно использовать свойство класса в качестве первичного ключа с именем «Id» или «{ClassName} Id».
public class Person
{
public int PersonID { get; set; } // <- will be used as primary key
public string PersonName { get; set; }
}
[Обязательный] атрибут
При применении к свойству класса домена база данных создаст столбец NOT NULL.
using System.ComponentModel.DataAnnotations;
public class Person
{
public int PersonID { get; set; }
[Required]
public string PersonName { get; set; }
}
Полученный столбец с ограничением NOT NULL:
Примечание. Его также можно использовать с asp.net-mvc в качестве атрибута проверки.
[MaxLength] и [MinLength]
Атрибут [MaxLength (int)] может применяться к свойству типа строки или массива класса домена. Entity Framework установит размер столбца на указанное значение.
using System.ComponentModel.DataAnnotations;
public class Person
{
public int PersonID { get; set; }
[MinLength(3), MaxLength(100)]
public string PersonName { get; set; }
}
Полученный столбец с указанной длиной столбца:
[MinLength (int)] - атрибут проверки, он не влияет на структуру базы данных. Если мы попытаемся вставить / обновить Person с PersonName длиной менее 3 символов, это сообщение не будет выполнено. Мы получим DbUpdateConcurrencyException
которое нам нужно будет обработать.
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'."
}
}
Оба атрибута [MaxLength] и [MinLength] также могут использоваться с asp.net-mvc в качестве атрибута проверки.
[Range (min, max)] атрибут
Указывает числовой минимальный и максимальный диапазон для свойства
using System.ComponentModel.DataAnnotations;
public partial class Enrollment
{
public int EnrollmentID { get; set; }
[Range(0, 4)]
public Nullable<decimal> Grade { get; set; }
}
Если мы попытаемся вставить / обновить класс со значением вне диапазона, это сообщение не будет выполнено. Мы получим DbUpdateConcurrencyException
которое нам нужно будет обработать.
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
}
}
Он также может использоваться с asp.net-mvc в качестве атрибута проверки.
Результат:
Атрибут [DatabaseGenerated]
Указывает, как база данных генерирует значения для свойства. Существует три возможных значения:
-
None
указывает, что значения не генерируются базой данных. -
Identity
указывает, что столбец является столбцом идентификации , который обычно используется для целых первичных ключей. -
Computed
указывает, что база данных генерирует значение для столбца.
Если значение имеет значение, отличное от None
, Entity Framework не будет вносить изменения, внесенные в свойство обратно в базу данных.
По умолчанию (на основе StoreGeneratedIdentityKeyConvention
) свойство целочисленного ключа будет рассматриваться как столбец идентификатора. Чтобы переопределить это соглашение и заставить его обрабатывать как столбец не идентичности, вы можете использовать атрибут DatabaseGenerated
со значением 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
}
Следующий SQL создает таблицу с вычисленным столбцом:
CREATE TABLE [Person] (
Name varchar(100) PRIMARY KEY,
DateOfBirth Date NOT NULL,
Age AS DATEDIFF(year, DateOfBirth, GETDATE())
)
GO
Чтобы создать объект для представления записей в приведенной выше таблице, вам нужно будет использовать атрибут DatabaseGenerated
со значением 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]
По соглашению Code-First Entity Framework создает столбец для каждого общедоступного свойства поддерживаемого типа данных и имеет как getter, так и setter. Аннотации [NotMapped] должны применяться к любым свойствам, для которых нам НЕ нужен столбец в таблице базы данных.
Примером свойства, которое мы не хотим хранить в базе данных, является полное имя студента, основанное на их имени и фамилии. Это можно вычислить «на лету», и нет необходимости хранить его в базе данных.
public string FullName => string.Format("{0} {1}", FirstName, LastName);
Свойство «FullName» имеет только getter и setter, поэтому по умолчанию Entity Framework НЕ создаст для него столбец.
Другим примером свойства, которое мы, возможно, не хотим хранить в базе данных, является «Средняя оценка» учащегося. Мы не хотим получать AverageGrade по запросу; вместо этого у нас может быть рутина в другом месте, которая ее вычисляет.
[NotMapped]
public float AverageGrade { set; get; }
«AverageGrade» должен быть помечен аннотацией [NotMapped] , иначе Entity Framework создаст для него столбец.
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; }
}
Для вышеупомянутого DbMigration.cs
мы увидим внутри DbMigration.cs
CreateTable(
"dbo.Students",
c => new
{
Id = c.Int(nullable: false, identity: true),
FirstName = c.String(),
LastName = c.String(),
})
.PrimaryKey(t => t.Id);
и в SQL Server Management Studio
Атрибут [Таблица]
[Table("People")]
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
}
Сообщает Entity Framework использовать конкретное имя таблицы вместо создания одного (то есть Person
или Persons
)
Мы также можем указать схему для таблицы, используя атрибут [Таблица]
[Table("People", Schema = "domain")]
Атрибут [Столбец]
public class Person
{
public int PersonID { get; set; }
[Column("NameOfPerson")]
public string PersonName { get; set; }
}
Сообщает Entity Framework вместо использования имени столбца вместо имени свойства. Вы также можете указать тип данных базы данных и порядок столбца в таблице:
[Column("NameOfPerson", TypeName = "varchar", Order = 1)]
public string PersonName { get; set; }
Атрибут [Index]
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
[Index]
public int Age { get; set; }
}
Создает индекс базы данных для столбца или набора столбцов.
[Index("IX_Person_Age")]
public int Age { get; set; }
Это создает индекс с определенным именем.
[Index(IsUnique = true)]
public int Age { get; set; }
Это создает уникальный индекс.
[Index("IX_Person_NameAndAge", 1)]
public int Age { get; set; }
[Index("IX_Person_NameAndAge", 2)]
public string PersonName { get; set; }
Это создает составной индекс, используя 2 столбца. Для этого вы должны указать одно и то же имя индекса и указать порядок столбцов.
Примечание . Атрибут Index был введен в Entity Framework 6.1. Если вы используете более раннюю версию, информация в этом разделе не применяется.
Атрибут [ForeignKey (string)]
Указывает имя пользовательского внешнего ключа, если требуется внешний ключ, не соответствующий соглашению EF.
public class Person
{
public int IdAddress { get; set; }
[ForeignKey(nameof(IdAddress))]
public virtual Address HomeAddress { get; set; }
}
Это также можно использовать, если у вас несколько отношений с одним типом объекта.
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; }
}
Без атрибутов ForeignKey
EF может их перепутать и использовать значение BillingAddressID
при извлечении MailingAddress
, или просто может возникнуть другое имя для столбца на основе его собственных соглашений об именах (например, Address_MailingAddress_Id
) и попытаться использовать это вместо этого (что приведет к ошибке, если вы используете это с существующей базой данных).
Атрибут [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; }
}
Определяет максимальную длину для строкового поля.
Примечание . Его также можно использовать с asp.net-mvc в качестве атрибута проверки.
Атрибут [Timestamp]
Атрибут [TimeStamp] может применяться только к одному свойству байтового массива в данном классе Entity. Entity Framework создаст в таблице базы данных столбец с нулевым значением в таблице базы данных для этого свойства. Entity Framework автоматически использует этот столбец TimeStamp при проверке параллелизма.
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]
Этот атрибут применяется к свойству класса. Вы можете использовать атрибут ConcurrencyCheck, если хотите использовать существующие столбцы для проверки параллелизма, а не отдельный столбец временной отметки для параллелизма.
using System.ComponentModel.DataAnnotations;
public class Author
{
public int AuthorId { get; set; }
[ConcurrencyCheck]
public string AuthorName { get; set; }
}
В приведенном выше примере атрибут ConcurrencyCheck применяется к свойству AuthorName класса Author. Итак, Code-First будет включать столбец AuthorName в команде update (where clause), чтобы проверить оптимистичный параллелизм.
Атрибут [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 может использоваться для идентификации двухсторонних отношений, когда между двумя сущностями существуют несколько двухсторонних отношений.
Он сообщает Entity Framework, какие свойства навигации должны соответствовать свойствам с другой стороны.
Entity Framework не знает, какая карта навигации имеет свойства с другой стороны, когда существуют несколько двунаправленных отношений между двумя объектами.
В качестве своего параметра ему нужно имя соответствующего свойства навигации в соответствующем классе.
Это также можно использовать для объектов, которые имеют отношение к другим объектам того же типа, образуя рекурсивное отношение.
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; }
}
Обратите также внимание на использование атрибута ForeignKey
для указания столбца, который используется для внешнего ключа в таблице. В первом примере два свойства класса Employee
могли иметь атрибут ForeignKey
для определения имен столбцов.
Атрибут [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; }
}
Пометьте класс как сложный тип в Entity Framework.
Сложные типы (или объекты ценности в проекте, управляемом доменом) не могут отслеживаться самостоятельно, но отслеживаются как часть объекта. Вот почему BlogDetails в этом примере не имеет свойства ключа.
Они могут быть полезны при описании сущностей домена на нескольких классах и разбиении этих классов на полный объект.