Tipos de entidad

Incluir un DbSet de un tipo en el contexto significa que se incluye en EF Core modelo de la aplicación. normalmente se hace referencia a un tipo como una entidad. EF Core leer y escribir instancias de entidad desde o hacia la base de datos y, si usa una base de datos relacional, EF Core puede crear tablas para las entidades a través de migraciones.

Inclusión de tipos en el modelo

Por convención, los tipos que se exponen en las propiedades de DbSet en el contexto se incluyen en el modelo como entidades. También se incluyen los tipos de entidad especificados en el método , al igual que los tipos que se encuentran explorando de forma recursiva las propiedades de navegación de otros tipos de OnModelCreating entidad detectados.

En el ejemplo de código siguiente, se incluyen todos los tipos:

  • Blog se incluye porque se expone en una propiedad DbSet en el contexto.
  • Post se incluye porque se detecta a través de la Blog.Posts propiedad de navegación .
  • AuditEntry porque se especifica en OnModelCreating .
internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

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

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

public class AuditEntry
{
    public int AuditEntryId { get; set; }
    public string Username { get; set; }
    public string Action { get; set; }
}

Exclusión de tipos del modelo

Si no desea incluir un tipo en el modelo, puede excluirlo:

[NotMapped]
public class BlogMetadata
{
    public DateTime LoadedFromDatabase { get; set; }
}

Exclusión de migraciones

Nota

La capacidad de excluir tablas de las migraciones se introdujo en EF Core 5.0.

A veces resulta útil tener el mismo tipo de entidad asignado en varios DbContext tipos. Esto es especialmente cierto cuando se usan contextos delimitados, para los que es habitual tener un tipo diferente para cada contexto enlazado.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<IdentityUser>()
        .ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}

Con esta configuración, las migraciones no crearán la tabla, pero todavía se incluyen en el modelo y AspNetUsers se pueden usar con IdentityUser normalidad.

Si necesita empezar a administrar la tabla de nuevo mediante migraciones, se debe crear una nueva migración donde AspNetUsers no se excluya. La siguiente migración contendrá ahora los cambios realizados en la tabla.

Nombre de la tabla

Por convención, cada tipo de entidad se configurará para asignarse a una tabla de base de datos con el mismo nombre que la propiedad DbSet que expone la entidad. Si no existe DbSet para la entidad determinada, se usa el nombre de clase.

Puede configurar manualmente el nombre de la tabla:

[Table("blogs")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

Esquema de tabla

Cuando se usa una base de datos relacional, las tablas se crean por convención en el esquema predeterminado de la base de datos. Por ejemplo, Microsoft SQL Server usará el dbo esquema (SQLite no admite esquemas).

Puede configurar las tablas que se crearán en un esquema específico como se muestra a continuación:

[Table("blogs", Schema = "blogging")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

En lugar de especificar el esquema para cada tabla, también puede definir el esquema predeterminado en el nivel de modelo con la API fluida:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("blogging");
}

Tenga en cuenta que establecer el esquema predeterminado también afectará a otros objetos de base de datos, como secuencias.

Visualización de la asignación

Los tipos de entidad se pueden asignar a vistas de base de datos mediante Fluent API.

Nota

EF asumirá que la vista a la que se hace referencia ya existe en la base de datos, no la creará automáticamente en una migración.

modelBuilder.Entity<Blog>()
    .ToView("blogsView", schema: "blogging");

La asignación a una vista quitará la asignación de tabla predeterminada, pero a partir de EF 5.0, el tipo de entidad también se puede asignar a una tabla explícitamente. En este caso, la asignación de consultas se usará para las consultas y la asignación de tabla se usará para las actualizaciones.

Sugerencia

Para probar los tipos de entidad asignados a vistas mediante el proveedor en memoria, así como asignarlos a una consulta a través de ToInMemoryQuery . Consulte un ejemplo que se puede ejecutar mediante esta técnica para obtener más detalles.

Asignación de funciones con valores de tabla

Es posible asignar un tipo de entidad a una función con valores de tabla (TVF) en lugar de a una tabla de la base de datos. Para ilustrar esto, vamos a definir otra entidad que represente el blog con varias entradas. En el ejemplo, la entidad no tiene clave,pero no tiene que serlo.

public class BlogWithMultiplePosts
{
    public string Url { get; set; }
    public int PostCount { get; set; }
}

A continuación, cree la siguiente función con valores de tabla en la base de datos, que devuelve solo blogs con varias entradas, así como el número de entradas asociadas a cada uno de estos blogs:

CREATE FUNCTION dbo.BlogsWithMultiplePosts()
RETURNS TABLE
AS
RETURN
(
    SELECT b.Url, COUNT(p.BlogId) AS PostCount
    FROM Blogs AS b
    JOIN Posts AS p ON b.BlogId = p.BlogId
    GROUP BY b.BlogId, b.Url
    HAVING COUNT(p.BlogId) > 1
)

Ahora, la BlogWithMultiplePosts entidad se puede asignar a esta función de la siguiente manera:

modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts");

Nota

Para asignar una entidad a una función con valores de tabla, la función debe ser sin parámetros.

Convencionalmente, las propiedades de entidad se asignarán a columnas que coincidan devueltas por tvf. Si las columnas devueltas por la TVF tienen nombres diferentes a la propiedad de entidad, las columnas de la entidad se pueden configurar mediante el método , al igual que cuando se asigna a una HasColumnName tabla normal.

Cuando el tipo de entidad se asigna a una función con valores de tabla, la consulta:

var query = from b in context.Set<BlogWithMultiplePosts>()
            where b.PostCount > 3
            select new { b.Url, b.PostCount };

Produce el siguiente SQL:

SELECT [b].[Url], [b].[PostCount]
FROM [dbo].[BlogsWithMultiplePosts]() AS [b]
WHERE [b].[PostCount] > 3

Comentarios de tabla

Puede establecer un comentario de texto arbitrario que se establece en la tabla de base de datos, lo que le permite documentar el esquema en la base de datos:

Nota

El establecimiento de comentarios a través de anotaciones de datos se introdujo EF Core 5.0.

[Comment("Blogs managed on the website")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

Tipos de entidad de tipo compartido

Nota

La compatibilidad con tipos de entidad de tipo compartido se introdujo en EF Core 5.0.

Los tipos de entidad que usan el mismo tipo CLR se conocen como tipos de entidad de tipo compartido. Estos tipos de entidad deben configurarse con un nombre único, que se debe proporcionar siempre que se utilice el tipo de entidad de tipo compartido, además del tipo CLR. Esto significa que la propiedad DbSet correspondiente debe implementarse mediante una llamada a Set .

internal class MyContext : DbContext
{
    public DbSet<Dictionary<string, object>> Blogs => Set<Dictionary<string, object>>("Blog");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.SharedTypeEntity<Dictionary<string, object>>(
            "Blog", bb =>
            {
                bb.Property<int>("BlogId");
                bb.Property<string>("Url");
                bb.Property<DateTime>("LastUpdated");
            });
    }
}