Создание и настройка модели
EF Core использует модель метаданных для описания того, как типы сущностей приложения сопоставляются с базовой базой данных. Эта модель построена с помощью набора соглашений — эвристики, которые ищут общие шаблоны. Затем модель можно настроить с помощью атрибутов сопоставления (также известных как заметки данных) и (или) вызовов ModelBuilder методов (также известных как простой API) в OnModelCreating, оба из которых переопределяют конфигурацию, выполняемую соглашениями.
Большинство конфигураций можно применить к модели, предназначенной для любого хранилища данных. Поставщики также могут включить конфигурацию, которая относится к конкретному хранилищу данных, и они также могут игнорировать конфигурацию, которая не поддерживается или не применяется. Документация по конфигурации для конкретного поставщика см. в разделе "Поставщики баз данных".
Совет
Примеры этой статьи можно просмотреть на сайте GitHub.
Использование текучего API для настройки модели
Вы можете переопределить OnModelCreating
метод в производном контексте и использовать api fluent для настройки модели. Это наиболее эффективный метод настройки, который позволяет задать конфигурацию без изменения ваших классов сущностей. Конфигурация текучего API имеет самый высокий приоритет и переопределяет соглашения и заметки к данным. Конфигурация применяется в том порядке, в каком порядке вызываются методы, и если возникают конфликты, последний вызов переопределит ранее указанную конфигурацию.
using Microsoft.EntityFrameworkCore;
namespace EFModeling.EntityProperties.FluentAPI.Required;
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
#region Required
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
#endregion
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Совет
Чтобы применить одну и ту же конфигурацию к нескольким объектам в модели, просмотрите массовую конфигурацию.
Группирование конфигурации
Чтобы уменьшить размер метода OnModelCreating
, вы можете извлечь все конфигурации для типа сущности в отдельный класс, реализующий IEntityTypeConfiguration<TEntity>.
public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
public void Configure(EntityTypeBuilder<Blog> builder)
{
builder
.Property(b => b.Url)
.IsRequired();
}
}
Затем просто вызовите метод Configure
из OnModelCreating
.
new BlogEntityTypeConfiguration().Configure(modelBuilder.Entity<Blog>());
Применение всех конфигураций в сборке
Вы можете применить все конфигурации, заданные в типах, реализующих IEntityTypeConfiguration
в определенной сборке.
modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);
Примечание.
Порядок, в котором будут применяться конфигурации, не определен. Поэтому этот метод следует использовать только в том случае, если порядок не имеет значения.
Использование EntityTypeConfigurationAttribute
типов сущностей
Вместо явного вызова Configure
вместо этого можно поместить в тип сущности, EntityTypeConfigurationAttribute чтобы EF Core могли найти и использовать соответствующую конфигурацию. Например:
[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Isbn { get; set; }
}
Этот атрибут означает, что EF Core будет использовать указанную реализацию IEntityTypeConfiguration
при включении типа сущности Book
в модель. Для включения типа сущности в модель применяется один из обычных механизмов. Например, создав свойство DbSet<TEntity> для типа сущности:
public class BooksContext : DbContext
{
public DbSet<Book> Books { get; set; }
//...
Или зарегистрировав его в OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>();
}
Примечание.
Типы EntityTypeConfigurationAttribute
не будут автоматически обнаружены в сборке. Типы сущностей необходимо добавить в модель до того, как атрибут будет обнаружен для этого типа сущности.
Использование заметок к данным для настройки модели
К классам и свойствам можно также применять определенные атрибуты (известные как заметки данных). Заметки к данным переопределяют соглашения, но они будут перезаписаны конфигурацией текучего API.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace EFModeling.EntityProperties.DataAnnotations.Annotations;
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
}
[Table("Blogs")]
public class Blog
{
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
}
Встроенные соглашения
EF Core включает множество соглашений о сборке моделей, которые включены по умолчанию. Все из них можно найти в списке классов, реализующих IConvention интерфейс. Однако этот список не включает соглашения, представленные сторонними поставщиками баз данных и подключаемыми модулями.
Приложения могут удалять или заменять любые из этих соглашений, а также добавлять новые пользовательские соглашения, которые применяют конфигурацию для шаблонов , которые не распознаются EF вне поля.
Совет
Приведенный ниже код поставляется из ModelBuildingConventionsSample.cs.
Удаление существующего соглашения
Иногда одно из встроенных соглашений может не подходить для приложения, в этом случае его можно удалить.
Совет
Если в модели не используются атрибуты сопоставления (заметки к данным aka) для настройки, все соглашения с именем, заканчивающиеся AttributeConvention
именем, можно безопасно удалить, чтобы ускорить построение модели.
Пример. Не создавайте индексы для столбцов внешнего ключа
Обычно имеет смысл создавать индексы для столбцов внешнего ключа (FK), поэтому для этого используется встроенное соглашение. ForeignKeyIndexConvention Просмотр представления отладки модели для Post
типа сущности с связями Blog
с иAuthor
, можно увидеть, что создаются два индекса— один для FK, а другой — для BlogId
AuthorId
FK.
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK Index
BlogId (no field, int) Shadow Required FK Index
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
Indexes:
AuthorId
BlogId
Однако индексы имеют издержки, и они не всегда подходят для создания всех столбцов FK. Для этого ForeignKeyIndexConvention
можно удалить при создании модели:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}
Глядя на представление отладки модели Post
сейчас, мы видим, что индексы на FK не созданы:
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK
BlogId (no field, int) Shadow Required FK
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
Если это необходимо, индексы по-прежнему могут быть явно созданы для внешних ключевых столбцов, используя IndexAttribute конфигурацию или конфигурацию.OnModelCreating
Представление отладки
Представление отладки построителя моделей можно получить в отладчике интегрированной среды разработки. Например, с Visual Studio:
Доступ к нему также можно получить непосредственно из кода, например для отправки представления отладки в консоль:
Console.WriteLine(context.Model.ToDebugString());
Представление отладки имеет короткую форму и длинную форму. Длинная форма также содержит все заметки, которые могут быть полезны, если необходимо просмотреть реляционные или метаданные конкретного поставщика. Кроме того, можно получить доступ к длинному представлению из кода:
Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));