Types d’entité sans clé

Remarque

Cette fonctionnalité a été ajoutée sous le nom de types de requête. Elle a ensuite été renommée types d’entités sans clé.

En plus des types d’entités standard, un modèle EF Core peut contenir des types d’entités sans clé, qui peuvent être utilisés pour effectuer des requêtes de base de données sur des données qui ne contiennent pas de valeurs de clé.

Définir les types d’entités sans clé

Les types d’entités sans clé peuvent être définis comme suit :

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

Caractéristiques des types d’entités sans clé

Les types d’entités sans clé prennent en charge la plupart des fonctionnalités de mappage des types d’entités standard, comme le mappage d’héritage et les propriétés de navigation. Sur les magasins relationnels, ils peuvent configurer les objets et colonnes de la base de données cibles via des méthodes d’API Fluent ou des annotations de données.

Toutefois, ils sont différents des types d’entités standard sur les points suivants :

  • Ils ne peuvent pas avoir de clé définie.
  • Leurs modifications ne sont jamais suivies dans DbContext et ils ne sont donc jamais insérés, mis à jour ou supprimés sur la base de données.
  • Ils ne sont jamais découverts par convention.
  • Ils prennent uniquement en charge un sous-ensemble de fonctionnalités de mappage de navigation, en particulier :
    • Ils ne peuvent jamais agir comme la fin principale d’une relation.
    • Ils peuvent ne pas avoir de navigations vers des entités détenues
    • Ils peuvent uniquement contenir des propriétés de navigation de référence pointant vers des entités régulières.
    • Les entités ne peuvent pas contenir de propriétés de navigation vers des types d’entités sans clé.
  • Ils doivent être configurés avec une annotation de données [Keyless] ou un appel de méthode .HasNoKey().
  • Ils peuvent être mappés à une requête de définition. Une requête de définition est une requête déclarée dans le modèle qui agit comme source de données pour un type d’entité sans clé.
  • Ils peuvent avoir une hiérarchie, mais elle doit être mappée en tant que TPH.
  • Ils ne peuvent pas utiliser le fractionnement de table ou le fractionnement d’entité.

Scénarios d’usage

Voici quelques-uns des principaux scénarios d’utilisation des types d’entités sans clé :

  • Utilisation comme type de retour pour les requêtes SQL.
  • Mappage aux vues de base de données qui ne contiennent pas de clé primaire.
  • Mappage aux tables qui n’ont pas de clé primaire définie.
  • Mappage aux requêtes définies dans le modèle.

Mappage à des objets de base de données

Le mappage d’un type d’entité sans clé à un objet de base de données est obtenu à l’aide de l’API Fluent ToTable ou ToView. Du point de vue EF Core, l’objet de base de données spécifié dans cette méthode est une vue, ce qui signifie qu’elle est traitée comme une source de requête en lecture seule et ne peut pas être la cible des opérations de mise à jour, d’insertion ou de suppression. Toutefois, cela ne signifie pas que l’objet de base de données est effectivement requis pour être une vue de base de données. Il peut également s’agir d’une table de base de données qui sera traitée en lecture seule. À l’inverse, pour les types d’entités standard, EF Core suppose qu’un objet de base de données spécifié dans la méthode ToTable peut être traité comme une table, ce qui signifie qu’il peut être utilisé comme source de requête, mais également ciblé par les opérations de mise à jour, de suppression et d’insertion. Dans les faits, vous pouvez spécifier le nom d’une vue de base de données dans ToTable et tout doit fonctionner correctement tant que la vue est configurée pour être pouvoir être mise à jour sur la base de données.

Exemple

L’exemple suivant montre comment utiliser des types d’entités sans clé pour interroger une vue de base de données.

Conseil

Vous pouvez afficher cet exemple sur GitHub.

Tout d’abord, nous définissons un modèle de blog et de publication simple :

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

Ensuite, nous définissons une vue de base de données simple qui nous permettra d’interroger le nombre de billets associés à chaque 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");

Ensuite, nous définissons une classe pour contenir le résultat de la vue de base de données :

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

Ensuite, nous configurons le type d’entité sans clé dans OnModelCreating avec l’API HasNoKey. Nous utilisons l’API de configuration Fluent pour configurer le mappage du type d’entité sans clé :

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

Ensuite, nous configurons DbContext pour inclure DbSet<T> :

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

Enfin, nous pouvons interroger la vue de base de données de manière standard :

var postCounts = db.BlogPostCounts.ToList();

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

Conseil

Notez que nous avons également défini une propriété de requête au niveau du contexte (DbSet) pour agir en tant que racine pour les requêtes sur ce type.

Conseil

Pour tester les types d’entités sans clé mappés aux vues à l’aide du fournisseur en mémoire, mappez-les à une requête via ToInMemoryQuery. Pour plus d’informations, consultez la documentation du fournisseur en mémoire.