Création et configuration d’un modèle

EF Core utilise un modèle de métadonnées pour décrire comment les types d’entités de l’application sont mappés à la base de données sous-jacente. Ce modèle est conçu à l’aide d’un ensemble de conventions heuristiques, qui recherchent des modèles courants. Le modèle peut ensuite être personnalisé à l’aide d’attributs de mappage (également appelés annotations de données) et/ou d’appels aux ModelBuilder méthodes (également appelées API Fluent) dans OnModelCreating, qui remplacent la configuration effectuée par des conventions.

La plupart des configurations peuvent être appliquées à un modèle ciblant n’importe quel magasin de données. Les fournisseurs peuvent également activer la configuration spécifique à un magasin de données en particulier et ignorer la configuration qui n’est pas prise en charge ou qui n’est pas applicable. Pour plus d’informations sur la configuration spécifique du fournisseur, consultez la section Fournisseurs de base de données.

Conseil

Vous pouvez afficher les exemples de cet article sur GitHub.

Utiliser l’API Fluent pour configurer un modèle

Vous pouvez substituer la méthode OnModelCreating dans le contexte dérivé et utiliser l’API Fluent pour configurer votre modèle. Il s’agit de la méthode de configuration la plus puissante, qui permet de spécifier une configuration sans modifier les classes d’entité. Dotée du niveau de priorité le plus élevé, la configuration de l’API Fluent remplace les conventions et les annotations de données. La configuration est appliquée dans l’ordre dans lequel les méthodes sont appelées et en cas de conflit, le dernier appel remplace la configuration spécifiée précédemment.

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

Conseil

Pour appliquer la même configuration à plusieurs objets du modèle, consultez Configuration en bloc.

Configuration du regroupement

Pour réduire la taille de la méthode OnModelCreating, toutes les configurations d’un type d’entité peuvent être extraites dans une classe distincte implémentant IEntityTypeConfiguration<TEntity>.

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

Ensuite, appelez simplement la méthode Configure à partir de OnModelCreating.

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

Appliquer toutes les configurations dans un assembly

Il est possible d’appliquer toutes les configurations spécifiées dans les types implémentés IEntityTypeConfiguration dans un assembly donné.

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

Remarque

L’ordre dans lequel les configurations seront appliquées n’est pas défini, par conséquent, cette méthode ne doit être utilisée que lorsque l’ordre n’est pas important.

Utiliser EntityTypeConfigurationAttribute sur les types d’entités

Au lieu d’appeler Configure explicitement, un EntityTypeConfigurationAttribute peut plutôt être placé sur le type d’entité afin qu’EF Core puisse rechercher et utiliser la configuration appropriée. Par exemple :

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

Cet attribut signifie qu’EF Core utilisera l’implémentation IEntityTypeConfiguration spécifiée chaque fois que le type d’entité Book est inclus dans un modèle. Le type d’entité est inclus dans un modèle à l’aide de l’un des mécanismes normaux. Par exemple, en créant une propriété DbSet<TEntity> pour le type d’entité :

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

    //...

Ou en l’inscrivant dans OnModelCreating :

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

Remarque

les types EntityTypeConfigurationAttribute ne seront pas détectés automatiquement dans un assembly. Les types d’entités doivent être ajoutés au modèle avant que l’attribut soit découvert sur ce type d’entité.

Utiliser des annotations de données pour configurer un modèle

Vous pouvez également appliquer des attributs (également appelés annotations de données) à vos classes et propriétés. Les annotations de données remplacent les conventions, mais elles sont remplacées par la configuration de l’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; }
}

Conventions intégrées

EF Core comprend de nombreuses conventions de génération de modèles activées par défaut. Vous pouvez les trouver dans la liste des classes qui implémentent l’interface IConvention. Toutefois, cette liste n’inclut pas les conventions introduites par les fournisseurs de base de données tiers et les plug-ins.

Les applications peuvent supprimer ou remplacer l’une de ces conventions, ainsi que d’ajouter de nouvelles conventions personnalisées qui appliquent la configuration pour les modèles qui ne sont pas reconnus par EF prêt à l’emploi.

Conseil

Le code indiqué ci-dessous provient de ModelBuildingConventionsSample.cs.

Supprimer une convention existante

Parfois, l’une des conventions intégrées peut ne pas convenir à votre application, auquel cas elle peut être supprimée.

Conseil

Si votre modèle n’utilise pas d’attributs de mappage (ou annotations de données) pour la configuration, toutes les conventions portant le nom se terminant par AttributeConvention peuvent être supprimées en toute sécurité pour accélérer la génération de modèles.

Exemple : ne créez pas d’index pour les colonnes de clé étrangère

Il est généralement judicieux de créer des index pour les colonnes de clé étrangère (FK) ; il existe donc une convention intégrée pour ceci : ForeignKeyIndexConvention. En examinant la vue de débogage du modèle pour un type d’entité Post avec des relations Blog et Author, nous pouvons voir que deux index sont créés : un pour la FK BlogId, et l’autre pour la FK AuthorId.

  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

Toutefois, les index ont une surcharge et il peut ne pas toujours être approprié de les créer pour toutes les colonnes FK. Pour ce faire, vous pouvez supprimer ForeignKeyIndexConvention lors de la génération du modèle :

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

Désormais, en examinant la vue de débogage du modèle pour Post, nous voyons que les index sur les FK n’ont pas été créés :

  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

Lorsque vous le souhaitez, les index peuvent toujours être créés explicitement pour les colonnes de clé étrangère, soit à l’aide de l’IndexAttribute ou via la configuration dans OnModelCreating.

Vue de débogage

La vue de débogage du générateur de modèles est accessible dans le débogueur de votre IDE. Par exemple, avec Visual Studio :

Accessing the model builder debug view from the Visual Studio debugger

Elle est également accessible directement à partir du code, par exemple pour envoyer la vue de débogage à la console :

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

La vue de débogage a une forme courte et une forme longue. La forme longue contient également toutes les annotations, qui peuvent être utiles si vous devez afficher les métadonnées relationnelles ou spécifiques au fournisseur. La vue longue est également accessible à partir du code :

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