Атрибуты сопоставления (заметки к данным aka) для связей
Атрибуты сопоставления используются для изменения или переопределения конфигурации, обнаруженной соглашениями о сборке моделей. Конфигурация, выполняемая атрибутами сопоставления, может быть переопределена API сборки модели, используемой в OnModelCreating
.
Внимание
В этом документе рассматриваются только атрибуты сопоставления в контексте конфигурации отношений. Другие варианты использования атрибутов сопоставления рассматриваются в соответствующих разделах более широкой документации по моделированию.
Совет
Приведенный ниже код можно найти в MappingAttributes.cs.
Где получить атрибуты сопоставления
Многие атрибуты сопоставления приходят из пространств имен System.ComponentModel.DataAnnotations и System.ComponentModel.DataAnnotations.Schema . Атрибуты в этих пространствах имен включены в состав базовой платформы во всех поддерживаемых версиях .NET, поэтому не требуют установки дополнительных пакетов NuGet. Эти атрибуты сопоставления обычно называются "заметками данных" и используются различными платформами, включая EF Core, EF6, ASP.NET Core MVC и т. д. Они также используются для проверки.
Использование заметок данных во многих технологиях и для сопоставления и проверки привело к различиям в семантике между технологиями. Все новые атрибуты сопоставления, предназначенные для EF Core, теперь относятся к EF Core, тем самым сохраняя их семантику и используйте простые и понятные. Эти атрибуты содержатся в пакете NuGet Microsoft.EntityFrameworkCore.Abstractions . Этот пакет включается в качестве зависимости всякий раз, когда используется основной пакет Microsoft.EntityFrameworkCore или один из связанных пакетов поставщика баз данных. Однако пакет Абстракции — это упрощенный пакет, на который можно ссылаться непосредственно с помощью кода приложения, не внося все ef Core и его зависимости.
RequiredAttribute
RequiredAttribute применяется к свойству, чтобы указать, что свойство не может быть null
. В контексте связей [Required]
обычно используется для свойства внешнего ключа. Это делает внешний ключ не допускаемым значением NULL, тем самым делая связь необходимой. Например, со следующими типами Post.BlogId
свойство делается ненулевой, и связь становится обязательной.
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[Required]
public string BlogId { get; set; }
public Blog Blog { get; init; }
}
Примечание.
При использовании ссылочных типов, допускающих значение NULL C#, BlogId
свойство в этом примере уже не допускает значения NULL, что означает, что [Required]
атрибут не будет влиять.
[Required]
на зависимой навигации имеет тот же эффект. То есть, делая внешний ключ не допускающим значение NULL, и тем самым делая связь необходимой. Например:
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
public string BlogId { get; set; }
[Required]
public Blog Blog { get; init; }
}
Если [Required]
на зависимой навигации и свойстве внешнего ключа находится в теневом состоянии, то теневое свойство делается ненулевой, тем самым делая связь необходимой. Рассмотрим пример.
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[Required]
public Blog Blog { get; init; }
}
Примечание.
Использование [Required]
на стороне основной навигации связи не влияет.
ForeignKeyAttribute
ForeignKeyAttribute используется для подключения свойства внешнего ключа с навигацией. [ForeignKey]
можно поместить в свойство внешнего ключа с именем зависимой навигации. Например:
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[ForeignKey(nameof(Blog))]
public string BlogKey { get; set; }
public Blog Blog { get; init; }
}
Кроме того, [ForeignKey]
можно поместить в зависимый или основной элемент навигации с именем свойства, которое будет использоваться в качестве внешнего ключа. Например:
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
public string BlogKey { get; set; }
[ForeignKey(nameof(BlogKey))]
public Blog Blog { get; init; }
}
Если [ForeignKey]
он помещается в навигацию, а указанное имя не соответствует имени свойства, то теневое свойство с таким именем будет создано для действия в качестве внешнего ключа. Например:
public class Blog
{
public string Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
[ForeignKey("BlogKey")]
public Blog Blog { get; init; }
}
InversePropertyAttribute
InversePropertyAttribute используется для подключения навигации с обратной структурой. Например, в следующих типах сущностей существует две связи между Blog
и Post
. Без какой-либо конфигурации соглашения EF не могут определить, какие навигации между двумя типами следует связать. Добавление [InverseProperty]
к одной из парных навигаций разрешает эту неоднозначность и позволяет EF создавать модель.
public class Blog
{
public int Id { get; set; }
[InverseProperty("Blog")]
public List<Post> Posts { get; } = new();
public int FeaturedPostId { get; set; }
public Post FeaturedPost { get; set; }
}
public class Post
{
public int Id { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; init; }
}
Внимание
[InverseProperty]
требуется только в том случае, если между теми же типами существует несколько связей. С одной связью две навигации объединяются автоматически.
DeleteBehaviorAttribute
По соглашению EF использует ClientSetNull
DeleteBehavior необязательные связи и Cascade
поведение необходимых связей. Это можно изменить, поместив DeleteBehaviorAttribute одну из навигаций связи. Например:
public class Blog
{
public int Id { get; set; }
public List<Post> Posts { get; } = new();
}
public class Post
{
public int Id { get; set; }
public int BlogId { get; set; }
[DeleteBehavior(DeleteBehavior.Restrict)]
public Blog Blog { get; init; }
}
Дополнительные сведения об каскадном удалении см. в статье об каскадном поведении .