Tipos de entidad

Incluir un DbSet de un tipo en el contexto significa que se incluye en el modelo de EF Core; normalmente se hace referencia a este tipo como una entidad. EF Core puede 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.

Incluir tipos en el modelo

Por convención, los tipos que se exponen en las propiedades DbSet del contexto se incluyen en el modelo como entidades. Los tipos de entidad especificados en el método OnModelCreating también se incluyen, como son los tipos que se encuentran explorando recursivamente las propiedades de navegación de otros tipos de 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 propiedad de navegación Blog.Posts.
  • 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; }
}

Excluir tipos del modelo

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

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

Excluir de migraciones

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

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

Con estas migraciones de configuración no se creará la tabla de AspNetUsers pero, IdentityUser, todavía se incluye en el modelo y se puede usar normalmente.

Si necesita empezar a administrar la tabla mediante migraciones de nuevo, se debe crear una nueva migración en la que no se excluye AspNetUsers. 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 asignar a una tabla de base de datos con el mismo nombre que la propiedad DbSet que expone la entidad. Si no existe ningún DbSet para la entidad especificada, 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 la tabla

Al usar 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 esquema dbo (SQLite no admite esquemas).

Puede configurar tablas que se crearán en un esquema específico de la siguiente manera:

[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.

Ver asignación

Los tipos de entidades se pueden asignar a vistas de bases de datos utilizando la API de Fluent.

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 el tipo de entidad también se puede asignar explícitamente a una tabla. En este caso, la asignación de consultas se usará para las consultas y la asignación de tablas se usará para las actualizaciones.

Sugerencia

Para probar los tipos de entidad sin clave asignados a vistas mediante el proveedor en memoria, asígnelos a una consulta a través de ToInMemoryQuery. Consulte los documentos del proveedor en memoria para obtener más información.

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 una tabla de la base de datos. Para ilustrar esto, vamos a definir otra entidad que representa el blog con varias entradas. En el ejemplo, la entidad no tiene clave, pero no tiene que ser.

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 publicaciones, 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 entidad BlogWithMultiplePosts 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 la entidad se asignarán a las columnas coincidentes devueltas por el TVF. Si las columnas devueltas por TVF tienen nombres diferentes a la propiedad de entidad, las columnas de la entidad se pueden configurar mediante el método HasColumnName, al igual que cuando se asigna a una 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:

[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

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 use el tipo de entidad de tipo compartido, además del tipo CLR. Esto significa que la propiedad DbSet correspondiente debe implementarse mediante una llamada 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");
            });
    }
}