Tipos de entidad sin llave

Nota:

Esta característica se agregó con el nombre de "tipos de consulta". Sin embargo, después, se le cambió de nombre a "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 de clave.

Definición de tipos de entidad sin clave

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

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

Características de los tipos de entidad sin clave

Los tipos de entidad sin clave 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, lo que los diferencia de los tipos de entidad normales es que:

  • No pueden tener una clave definida.
  • Nunca se realiza un seguimiento de los cambios en DbContext y, por tanto, nunca se insertan, actualizan o eliminan en la base de datos.
  • Por convención, nunca se detectan.
  • Solo admiten un subconjunto de funcionalidades de asignación de navegación, específicamente:
    • Nunca pueden actuar como el extremo principal 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 clave.
  • Debe configurarse con una anotación de datos [Keyless] o una llamada de método .HasNoKey().
  • Se puede asignar a una definición de consulta. Una definición de consulta 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 tabla por jerarquía.
  • 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 clave son:

  • Actuar como tipo de valor devuelto en consultas SQL.
  • Asignar a vistas de base de datos que no contienen una clave principal.
  • Asignar a tablas que no tienen definida una clave principal.
  • Asignar a consultas definidas en el modelo.

Asignación 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 API fluida ToTable o ToView. 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 sea realmente necesario para 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 método ToTable se puede tratar como una tabla, lo que significa que se puede usar como origen de consulta, pero también ser el destino de 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 clave 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:

db.Database.ExecuteSqlRaw(
    @"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");

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

Después, configuramos el tipo de entidad sin clave en OnModelCreating mediante la API HasNoKey. Usamos la API Fluent Configuration para configurar la asignación para el tipo de entidad sin clave:

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 que incluya 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 = db.BlogPostCounts.ToList();

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