Creazione e configurazione di un modello
EF Core usa un modello di metadati per descrivere il mapping dei tipi di entità dell'applicazione al database sottostante. Questo modello viene creato usando un set di convenzioni , euristica che cercano modelli comuni. Il modello può quindi essere personalizzato usando attributi di mapping (noti anche come annotazioni di dati) e/o chiamate ai ModelBuilder metodi (noti anche come API Fluent) in OnModelCreating, entrambi i quali eseguiranno l'override della configurazione eseguita dalle convenzioni.
La maggior parte della configurazione può essere applicata a un modello destinato a qualsiasi archivio dati. I provider possono anche abilitare la configurazione specifica di un archivio dati specifico e possono anche ignorare la configurazione non supportata o non applicabile. Per la documentazione sulla configurazione specifica del provider, vedere la sezione Provider di database .
Suggerimento
È possibile visualizzare gli esempi di questo articolo in GitHub.
Usare l'API Fluent per configurare un modello
È possibile eseguire l'override del OnModelCreating
metodo nel contesto derivato e usare l'API Fluent per configurare il modello. Questo è il metodo di configurazione più efficace e consente di specificare la configurazione senza modificare le classi di entità. La configurazione dell'API Fluent ha la precedenza più elevata e sostituisce le convenzioni e le annotazioni dei dati. La configurazione viene applicata nell'ordine in cui vengono chiamati i metodi e, in caso di conflitti, la chiamata più recente eseguirà l'override della configurazione specificata in precedenza.
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; }
}
Suggerimento
Per applicare la stessa configurazione a più oggetti nel modello, vedere configurazione in blocco.
Raggruppamento delle configurazioni
Per ridurre le dimensioni del metodo OnModelCreating
, è possibile estrarre tutte le configurazioni di un tipo di entità in una classe separata che implementa IEntityTypeConfiguration<TEntity>.
public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
public void Configure(EntityTypeBuilder<Blog> builder)
{
builder
.Property(b => b.Url)
.IsRequired();
}
}
Richiamare quindi il metodo Configure
da OnModelCreating
.
new BlogEntityTypeConfiguration().Configure(modelBuilder.Entity<Blog>());
Applicazione di tutte le configurazioni in un assembly
È possibile applicare tutte le configurazioni specificate nei tipi che implementano IEntityTypeConfiguration
in un determinato assembly.
modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);
Nota
L'ordine in cui verranno applicate le configurazioni non è definito, pertanto questo metodo deve essere usato solo quando l'ordine non è importante.
Uso dei EntityTypeConfigurationAttribute
tipi di entità
Anziché chiamare Configure
in modo esplicito , un EntityTypeConfigurationAttribute oggetto può invece essere inserito nel tipo di entità in modo che EF Core possa trovare e usare la configurazione appropriata. Ad esempio:
[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Isbn { get; set; }
}
Questo attributo significa che EF Core userà l'implementazione specificata IEntityTypeConfiguration
ogni volta che il Book
tipo di entità viene incluso in un modello. Il tipo di entità è incluso in un modello usando uno dei meccanismi normali. Ad esempio, creando una DbSet<TEntity> proprietà per il tipo di entità:
public class BooksContext : DbContext
{
public DbSet<Book> Books { get; set; }
//...
In alternativa, registrandolo in OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>();
}
Nota
EntityTypeConfigurationAttribute
I tipi non verranno individuati automaticamente in un assembly. I tipi di entità devono essere aggiunti al modello prima che l'attributo venga individuato in tale tipo di entità.
Usare le annotazioni dei dati per configurare un modello
È anche possibile applicare determinati attributi (noti come Annotazioni dati) alle classi e alle proprietà. Le annotazioni dei dati sostituiranno le convenzioni, ma saranno a loro volta ignorate dalla configurazione dell'API Fluent.
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; }
}
Convenzioni predefinite
EF Core include molte convenzioni di compilazione di modelli abilitate per impostazione predefinita. È possibile trovarli tutti nell'elenco delle classi che implementano l'interfaccia IConvention . Tuttavia, tale elenco non include convenzioni introdotte da provider di database e plug-in di terze parti.
Le applicazioni possono rimuovere o sostituire una di queste convenzioni, nonché aggiungere nuove convenzioni personalizzate che applicano la configurazione per i modelli non riconosciuti da Entity Framework.
Suggerimento
Il codice illustrato di seguito deriva da ModelBuildingConventionsSample.cs.
Rimozione di una convenzione esistente
A volte una delle convenzioni predefinite potrebbe non essere appropriata per l'applicazione, nel qual caso può essere rimossa.
Suggerimento
Se il modello non usa attributi di mapping (ovvero annotazioni di dati) per la configurazione, tutte le convenzioni con il nome che terminano AttributeConvention
possono essere rimosse in modo sicuro per velocizzare la compilazione del modello.
Esempio: Non creare indici per le colonne chiave esterna
In genere è opportuno creare indici per le colonne di chiave esterna (FK) e quindi esiste una convenzione predefinita per questo: ForeignKeyIndexConvention. Esaminando la vista di debug del modello per un Post
tipo di entità con relazioni con Blog
e Author
, è possibile vedere che vengono creati due indici, uno per la BlogId
chiave FK e l'altro per FKAuthorId
.
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
Tuttavia, gli indici presentano un sovraccarico e potrebbe non essere sempre appropriato crearli per tutte le colonne FK. A tale scopo, è possibile rimuovere l'oggetto ForeignKeyIndexConvention
durante la compilazione del modello:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}
Esaminando la visualizzazione di debug del modello per Post
il momento, si noterà che gli indici negli FK non sono stati creati:
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
Quando si desidera, gli indici possono comunque essere creati in modo esplicito per le colonne di chiave esterna, usando o con la IndexAttribute configurazione in OnModelCreating
.
Visualizzazione debug
È possibile accedere alla visualizzazione di debug del generatore di modelli nel debugger dell'IDE. Ad esempio, con Visual Studio:
È anche possibile accedervi direttamente dal codice, ad esempio per inviare la visualizzazione di debug alla console:
Console.WriteLine(context.Model.ToDebugString());
La visualizzazione di debug ha una forma breve e una maschera lunga. Il modulo lungo include anche tutte le annotazioni, che possono essere utili se è necessario visualizzare metadati relazionali o specifici del provider. È possibile accedere alla visualizzazione lunga anche dal codice:
Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));