Compartir a través de


Tipos de entidad sin claves

Nota:

Esta característica se agregó bajo el nombre de los tipos de consulta. Posteriormente se cambió el nombre a los tipos de entidad sin clave.

Además de los tipos de entidad normales, un modelo de EF Core puede contener tipos de entidad sin clave, que se pueden usar para llevar a cabo consultas de base de datos en datos que no contienen valores clave.

Definición de tipos de entidad sin claves

Los tipos de entidad sin claves se pueden definir de la manera siguiente:

[Keyless]
public class BlogPostsCount
{
    public string BlogName { get; set; }
    public int PostCount { get; set; }
}

Características de los tipos de entidad sin claves

Los tipos de entidad sin claves admiten muchas de las mismas funcionalidades de asignación que los tipos de entidad normales, como la asignación de herencia y las propiedades de navegación. En los almacenes relacionales, pueden configurar los objetos y columnas de base de datos de destino a través de métodos de API fluidas o anotaciones de datos.

Sin embargo, son diferentes de los tipos de entidad normales en que:

  • No se puede tener definida una clave.
  • Nunca se realiza un seguimiento de los cambios en DbContext y, por lo tanto, nunca se insertan, actualizan o eliminan en la base de datos.
  • Nunca se descubren por convención.
  • Solo admite un subconjunto de capacidades de mapeo de navegación, específicamente:
    • Quizás nunca funcionen como el principal fin de una relación.
    • Es posible que no tengan navegaciones a entidades de propiedad.
    • Solo pueden contener propiedades de navegación de referencia que apunten a entidades normales.
    • Las entidades no pueden contener propiedades de navegación a tipos de entidad sin claves.
  • Debe configurarse con una [Keyless] anotación de datos o una .HasNoKey() llamada de método.
  • Se puede asignar a una consulta definitoria. Una consulta de definición es una consulta declarada en el modelo que actúa como origen de datos para un tipo de entidad sin clave.
  • Puede tener una jerarquía, pero debe asignarse como TPH.
  • No se puede usar la división de tablas ni la división de entidades.

Escenarios de uso

Algunos de los principales escenarios de uso para los tipos de entidad sin claves son:

  • Servir como tipo de valor devuelto para las consultas SQL.
  • Asignación a vistas de base de datos que no contienen una clave principal.
  • Asignación a tablas que no tienen especificada una clave principal.
  • Mapeo a consultas definidas en el modelo.

Mapeo a objetos de base de datos

La asignación de un tipo de entidad sin clave a un objeto de base de datos se logra mediante la ToTable o ToView API fluente. Desde la perspectiva de EF Core, el objeto de base de datos especificado en este método es una vista, lo que significa que se trata como un origen de consulta de solo lectura y no puede ser el destino de las operaciones de actualización, inserción o eliminación. Sin embargo, esto no significa que el objeto de base de datos tenga que ser una vista de base de datos. Como alternativa, puede ser una tabla de base de datos que se tratará como de solo lectura. Por el contrario, para los tipos de entidad normales, EF Core supone que un objeto de base de datos especificado en el ToTable método se puede tratar como una tabla, lo que significa que se puede usar como origen de consulta, pero también dirigido por operaciones de actualización, eliminación e inserción. De hecho, puede especificar el nombre de una vista de base de datos en ToTable y todo debería funcionar bien siempre que la vista esté configurada para que sea actualizable en la base de datos.

Ejemplo

En el ejemplo siguiente se muestra cómo usar tipos de entidad sin claves para consultar una vista de base de datos.

Sugerencia

Puede ver un ejemplo de este artículo en GitHub.

En primer lugar, definimos un modelo sencillo de blog y publicación:

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public ICollection<Post> Posts { get; set; }
}

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

A continuación, definimos una vista de base de datos sencilla que nos permitirá consultar el número de entradas asociadas a cada blog:

await db.Database.ExecuteSqlRawAsync(
    @"CREATE VIEW View_BlogPostCounts AS
                SELECT b.Name, Count(p.PostId) as PostCount
                FROM Blogs b
                JOIN Posts p on p.BlogId = b.BlogId
                GROUP BY b.Name");

A continuación, definimos una clase para contener el resultado de la vista de base de datos:

public class BlogPostsCount
{
    public string BlogName { get; set; }
    public int PostCount { get; set; }
}

A continuación, configuramos el tipo de entidad sin clave en OnModelCreating mediante la HasNoKey API. Usamos la API de configuración fluida para configurar la asignación del tipo de entidad sin claves.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<BlogPostsCount>(
            eb =>
            {
                eb.HasNoKey();
                eb.ToView("View_BlogPostCounts");
                eb.Property(v => v.BlogName).HasColumnName("Name");
            });
}

A continuación, configuramos el DbContext para incluir el DbSet<T>.

public DbSet<BlogPostsCount> BlogPostCounts { get; set; }

Por último, podemos consultar la vista de base de datos de la manera estándar:

var postCounts = await db.BlogPostCounts.ToListAsync();

foreach (var postCount in postCounts)
{
    Console.WriteLine($"{postCount.BlogName} has {postCount.PostCount} posts.");
    Console.WriteLine();
}

Sugerencia

Tenga en cuenta que también hemos definido una propiedad de consulta de nivel de contexto (DbSet) para que actúe como raíz para las consultas en este tipo.

Sugerencia

Para probar tipos de entidades sin claves que se asignan a las vistas usando el proveedor en memoria, asígnelos a una consulta mediante ToInMemoryQuery. Consulte los documentos del proveedor en memoria para obtener más información.