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.
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ć Configure
metodę 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:
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));