Поделиться через


Атрибуты сопоставления (заметки к данным 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; }
}

Дополнительные сведения об каскадном удалении см. в статье об каскадном поведении .