Compartir a través de


Creación y configuración de un modelo

EF Core usa un modelo de metadatos para describir cómo se asignan los tipos de entidad de la aplicación a la base de datos subyacente. Este modelo se crea mediante un conjunto de convenciones : heurística que buscan patrones comunes. A continuación, el modelo se puede personalizar mediante atributos de asignación (también conocidos como anotaciones de datos) o llamadas a los ModelBuilder métodos (también conocidos como API fluidas) en OnModelCreating, ambos anularán la configuración realizada por las convenciones.

La mayoría de la configuración se puede aplicar a un modelo que tenga como destino cualquier almacén de datos. Los proveedores también pueden habilitar la configuración específica de un almacén de datos determinado y también pueden omitir la configuración que no se admite o no es aplicable. Para obtener documentación sobre la configuración específica del proveedor, consulte la sección Proveedores de bases de datos .

Sugerencia

Puede ver los ejemplos de este artículo en GitHub.

Uso de fluent API para configurar un modelo

Puede sobrescribir el método OnModelCreating en su contexto derivado y usar la API fluida para configurar su modelo. Este es el método de configuración más eficaz y permite especificar la configuración sin modificar las clases de entidad. La configuración de fluent API tiene la prioridad más alta y invalidará las convenciones y las anotaciones de datos. La configuración se aplica en el orden en que se llama a los métodos y si hay conflictos, la llamada más reciente invalidará la configuración especificada anteriormente.

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

Sugerencia

Para aplicar la misma configuración a varios objetos del modelo, consulte configuración masiva.

Configuración de agrupación

Para reducir el tamaño del método OnModelCreating, toda la configuración de un tipo de entidad se puede extraer en una clase independiente que implemente IEntityTypeConfiguration<TEntity>.

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

A continuación, simplemente invoque el Configure método desde OnModelCreating.

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

Aplicación de todas las configuraciones en un ensamblado

Es posible aplicar toda la configuración especificada en los tipos que implementan IEntityTypeConfiguration en un ensamblado determinado.

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

Nota:

El orden en el que se aplicarán las configuraciones no está definido, por lo que este método solo se debe usar cuando no importa el orden.

Uso de EntityTypeConfigurationAttribute en tipos de entidad

En lugar de llamar explícitamente a Configure, un EntityTypeConfigurationAttribute puede colocarse en el tipo de entidad para que EF Core pueda encontrar y usar la configuración adecuada. Por ejemplo:

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

Este atributo significa que EF Core usará la implementación especificada IEntityTypeConfiguration siempre que el Book tipo de entidad se incluya en un modelo. El tipo de entidad se incluye en un modelo mediante uno de los mecanismos normales. Por ejemplo, mediante la creación de una DbSet<TEntity> propiedad para el tipo de entidad:

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

    //...

O registrándolo en OnModelCreating:

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

Nota:

EntityTypeConfigurationAttribute Los tipos no se detectarán automáticamente en un ensamblado. Los tipos de entidad deben agregarse al modelo antes de que se detecte el atributo en ese tipo de entidad.

Uso de anotaciones de datos para configurar un modelo

También puede aplicar determinados atributos ( conocidos como anotaciones de datos) a las clases y propiedades. Las anotaciones de datos invalidarán las convenciones, pero serán invalidadas por la configuración de Fluent 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; }
}

Convenciones integradas

EF Core incluye muchas convenciones de creación de modelos habilitadas de forma predeterminada. Puede encontrar todos ellos en la lista de clases que implementan la IConvention interfaz . Sin embargo, esa lista no incluye convenciones introducidas por proveedores y complementos de bases de datos de terceros.

Las aplicaciones pueden quitar o reemplazar cualquiera de estas convenciones, así como agregar nuevas convenciones personalizadas que apliquen la configuración de patrones que EF no reconoce de forma predeterminada.

Sugerencia

El código que se muestra a continuación procede de ModelBuildingConventionsSample.cs.

Eliminación de una convención existente

A veces, es posible que una de las convenciones integradas no sea adecuada para la aplicación, en cuyo caso se puede quitar.

Sugerencia

Si el modelo no usa atributos de asignación (también conocidos como anotaciones de datos) para la configuración, todas las convenciones con el nombre que terminan en AttributeConvention se pueden quitar de forma segura para acelerar la creación de modelos.

Ejemplo: No crear índices para columnas de clave externa

Normalmente tiene sentido crear índices para columnas de clave externa (FK) y, por lo tanto, hay una convención integrada para esto: ForeignKeyIndexConvention. Al examinar la vista de depuración del modelo para un Post tipo de entidad con relaciones con Blog y Author, podemos ver que se crean dos índices: uno para el BlogId FK y el otro para el 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

Sin embargo, los índices tienen sobrecarga y es posible que no siempre sea adecuado crearlos para todas las columnas de FK. Para lograrlo, ForeignKeyIndexConvention se puede quitar al compilar el modelo:

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

Al examinar la vista de depuración del modelo por Post ahora, vemos que no se han creado los índices en los 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

Cuando se desea, los índices todavía se pueden crear explícitamente para las columnas de clave externa, ya sea utilizando IndexAttribute o configurando en OnModelCreating.

Vista de depuración

La vista de depuración del generador de modelos está disponible en el depurador de su entorno de desarrollo integrado. Por ejemplo, con Visual Studio:

Acceso a la vista de depuración del generador de modelos desde el depurador de Visual Studio

También se puede acceder directamente desde el código, por ejemplo, para enviar la vista de depuración a la consola:

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

La vista de depuración tiene un formato corto y un formulario largo. El formato largo también incluye todas las anotaciones, lo que podría ser útil si necesita ver metadatos relacionales o específicos del proveedor. También se puede acceder a la vista larga desde el código:

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