Tworzenie i konfigurowanie modelu

Program EF Core używa modelu metadanych do opisania sposobu mapowania typów jednostek aplikacji na bazową bazę danych. Ten model jest tworzony przy użyciu zestawu konwencji — heurystyki, które szukają typowych wzorców. Następnie model można dostosować przy użyciu atrybutów mapowania (nazywanych również adnotacjami danych) i/lub wywołań ModelBuilder metod (nazywanych również płynnym interfejsem API) w systemie OnModelCreating, z których obie zastąpią konfigurację wykonywaną przez konwencje.

Większość konfiguracji można zastosować do modelu przeznaczonego dla dowolnego magazynu danych. Dostawcy mogą również włączyć konfigurację specyficzną dla określonego magazynu danych, a także zignorować konfigurację, która nie jest obsługiwana lub nie dotyczy. Aby uzyskać dokumentację dotyczącą konfiguracji specyficznej dla dostawcy, zobacz sekcję Dostawcy baz danych.

Napiwek

Przykłady tego artykułu można wyświetlić w witrynie GitHub.

Konfigurowanie modelu przy użyciu płynnego interfejsu API

Możesz zastąpić metodę OnModelCreating w kontekście pochodnym i użyć płynnego interfejsu API do skonfigurowania modelu. Jest to najbardziej zaawansowana metoda konfiguracji, która umożliwia określanie konfiguracji bez modyfikowania klas jednostek. Konfiguracja płynnego interfejsu API ma najwyższy priorytet i zastępuje konwencje i adnotacje danych. Konfiguracja jest stosowana w kolejności wywoływania metod i jeśli występują konflikty, najnowsze wywołanie zastąpi wcześniej określoną konfigurację.

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; }
}

Napiwek

Aby zastosować tę samą konfigurację do wielu obiektów w modelu, zobacz konfigurację zbiorczą.

Grupowanie konfiguracji

Aby zmniejszyć wielkość metody OnModelCreating, można wyodrębnić całą konfigurację dla typu jednostki do oddzielnej klasy implementującej interfejs IEntityTypeConfiguration<TEntity>.

public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
    public void Configure(EntityTypeBuilder<Blog> builder)
    {
        builder
            .Property(b => b.Url)
            .IsRequired();
    }
}

Następnie wystarczy wywołać metodę Configure z metody OnModelCreating.

new BlogEntityTypeConfiguration().Configure(modelBuilder.Entity<Blog>());

Stosowanie wszystkich konfiguracji w zestawie

Można stosować całą konfigurację określoną w typach implementujących interfejs IEntityTypeConfiguration w danym zestawie.

modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);

Uwaga

Kolejność stosowania konfiguracji jest niezdefiniowana, więc tej metody należy używać tylko wtedy, gdy ta kolejność nie ma znaczenia.

Używanie EntityTypeConfigurationAttribute w typach jednostek

Zamiast jawnie wywoływać Configuremetodę EntityTypeConfigurationAttribute , zamiast tego można umieścić w typie jednostki, tak aby program EF Core mógł znaleźć i użyć odpowiedniej konfiguracji. Przykład:

[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Isbn { get; set; }
}

Ten atrybut oznacza, że program EF Core będzie używać określonej IEntityTypeConfiguration implementacji za każdym razem, gdy Book typ jednostki jest uwzględniony w modelu. Typ jednostki jest uwzględniany w modelu przy użyciu jednego z normalnych mechanizmów. Na przykład przez utworzenie DbSet<TEntity> właściwości dla typu jednostki:

public class BooksContext : DbContext
{
    public DbSet<Book> Books { get; set; }

    //...

Lub rejestrując go w programie OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Book>();
}

Uwaga

EntityTypeConfigurationAttribute typy nie zostaną automatycznie odnalezione w zestawie. Typy jednostek należy dodać do modelu, zanim atrybut zostanie odnaleziony w tym typie jednostki.

Konfigurowanie modelu przy użyciu adnotacji danych

Do klas i właściwości można również zastosować pewne atrybuty (znane jako adnotacje danych). Adnotacje danych zastępują konwencje, ale są zastępowane przez konfigurację płynnego interfejsu 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; }
}

Konwencje wbudowane

Program EF Core zawiera wiele konwencji tworzenia modeli, które są domyślnie włączone. Wszystkie z nich można znaleźć na liście klas, które implementują IConvention interfejs. Jednak ta lista nie zawiera konwencji wprowadzonych przez dostawców i wtyczek baz danych innych firm.

Aplikacje mogą usuwać lub zastępować dowolną z tych konwencji, a także dodawać nowe konwencje niestandardowe, które stosują konfigurację dla wzorców, które nie są rozpoznawane przez ef out of the box.

Napiwek

Poniższy kod pochodzi z pliku ModelBuildingConventionsSample.cs.

Usuwanie istniejącej konwencji

Czasami jedna z wbudowanych konwencji może nie być odpowiednia dla aplikacji, w tym przypadku można ją usunąć.

Napiwek

Jeśli model nie używa atrybutów mapowania (aka adnotacji danych) do konfiguracji, wszystkie konwencje o nazwie kończącej AttributeConvention się można bezpiecznie usunąć, aby przyspieszyć tworzenie modelu.

Przykład: nie twórz indeksów dla kolumn kluczy obcych

Zwykle warto utworzyć indeksy dla kolumn klucza obcego (FK), dlatego istnieje wbudowana konwencja dla tego: ForeignKeyIndexConvention. Patrząc na widok debugowania modelu dla Post typu jednostki z relacjami z Blog i Author, możemy zobaczyć, że dwa indeksy są tworzone — jeden dla BlogId klucza FK, a drugi dla AuthorId klucza 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

Jednak indeksy mają obciążenie i może nie zawsze być odpowiednie do utworzenia ich dla wszystkich kolumn FK. Aby to osiągnąć, ForeignKeyIndexConvention można go usunąć podczas kompilowania modelu:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}

Patrząc na widok debugowania modelu na Post razie, widzimy, że indeksy na zestawach FKs nie zostały utworzone:

  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

W razie potrzeby indeksy mogą być nadal jawnie tworzone dla kolumn kluczy obcych przy użyciu elementu IndexAttribute lub z konfiguracją w programie OnModelCreating.

Widok debugowania

Dostęp do widoku debugowania konstruktora modelu można uzyskać w debugerze środowiska IDE. Na przykład w programie Visual Studio:

Accessing the model builder debug view from the Visual Studio debugger

Dostęp do niego można również uzyskać bezpośrednio z kodu, na przykład w celu wysłania widoku debugowania do konsoli:

Console.WriteLine(context.Model.ToDebugString());

Widok debugowania ma krótką formę i długi formularz. Długi formularz zawiera również wszystkie adnotacje, które mogą być przydatne, jeśli musisz wyświetlić metadane relacyjne lub specyficzne dla dostawcy. Dostęp do długiego widoku można uzyskać również z poziomu kodu:

Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));