Tipi di entità senza chiave

Nota

Questa funzionalità è stata aggiunta sotto il nome dei tipi di query. In seguito è stato rinominato in tipi di entità senza chiave.

Oltre ai tipi di entità regolari, un modello EF Core può contenere tipi di entità senza chiave, che possono essere usati per eseguire query di database su dati che non contengono valori di chiave.

Definizione dei tipi di entità senza chiave

I tipi di entità senza chiave possono essere definiti come segue:

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

Caratteristiche dei tipi di entità senza chiave

I tipi di entità senza chiave supportano molte delle stesse funzionalità di mapping dei tipi di entità regolari, ad esempio il mapping di ereditarietà e le proprietà di navigazione. Negli archivi relazionali possono configurare gli oggetti e le colonne di database di destinazione tramite metodi API Fluent o annotazioni di dati.

Tuttavia, sono diversi dai tipi di entità regolari in quanto:

  • Impossibile definire una chiave.
  • Non vengono mai rilevate modifiche in DbContext e pertanto non vengono mai inserite, aggiornate o eliminate nel database.
  • Non vengono mai scoperte per convenzione.
  • Supporta solo un subset di funzionalità di mapping di spostamento, in particolare:
    • Non possono mai agire come la fine principale di una relazione.
    • Potrebbero non avere spostamenti alle entità di proprietà
    • Possono contenere solo proprietà di navigazione di riferimento che puntano a entità regolari.
    • Le entità non possono contenere proprietà di navigazione ai tipi di entità senza chiave.
  • Deve essere configurato con un'annotazione [Keyless] dati o una .HasNoKey() chiamata al metodo.
  • È possibile eseguire il mapping a una query di definizione. Una query che definisce è una query dichiarata nel modello che funge da origine dati per un tipo di entità senza chiave.
  • Può avere una gerarchia, ma deve essere mappata come TPH.
  • Impossibile utilizzare la suddivisione delle tabelle o la suddivisione di entità.

Scenari di utilizzo

Alcuni degli scenari di utilizzo principali per i tipi di entità senza chiave sono:

  • Funge da tipo restituito per le query SQL.
  • Mapping a viste di database che non contengono una chiave primaria.
  • Mapping a tabelle che non dispongono di una chiave primaria definita.
  • Mapping alle query definite nel modello.

Mapping a oggetti di database

Il mapping di un tipo di entità senza chiave a un oggetto di database viene ottenuto tramite l'API ToTable fluent o ToView . Dal punto di vista di EF Core, l'oggetto di database specificato in questo metodo è una visualizzazione, ovvero viene considerato come origine di query di sola lettura e non può essere la destinazione delle operazioni di aggiornamento, inserimento o eliminazione. Tuttavia, ciò non significa che l'oggetto di database sia effettivamente necessario essere una vista di database. In alternativa, può essere una tabella di database che verrà considerata di sola lettura. Al contrario, per i tipi di entità regolari, EF Core presuppone che un oggetto di database specificato nel ToTable metodo possa essere considerato come una tabella, ovvero che può essere usato come origine di query, ma anche destinato alle operazioni di aggiornamento, eliminazione e inserimento. In effetti, è possibile specificare il nome di una vista di database in ToTable e tutti gli elementi devono funzionare correttamente, purché la vista sia configurata per essere aggiornabile nel database.

Esempio

Nell'esempio seguente viene illustrato come usare i tipi di entità senza chiave per eseguire query su una vista di database.

Suggerimento

È possibile visualizzare l'esempio di questo articolo in GitHub.

Prima di tutto, definiamo un semplice modello di blog e post:

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

Successivamente, definiamo una visualizzazione di database semplice che consentirà di eseguire query sul numero di post associati a ogni 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");

Definire quindi una classe per contenere il risultato dalla vista del database:

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

Configurare quindi il tipo di entità senza chiave in OnModelCreating usando l'API HasNoKey . Si usa l'API di configurazione Fluent per configurare il mapping per il tipo di entità senza chiave:

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

Configurare quindi per DbContext includere :DbSet<T>

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

Infine, è possibile eseguire una query sulla vista del database nel modo standard:

var postCounts = db.BlogPostCounts.ToList();

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

Suggerimento

Si noti che è stata definita anche una proprietà di query a livello di contesto (DbSet) per fungere da radice per le query su questo tipo.

Suggerimento

Per testare i tipi di entità senza chiave mappati alle viste usando il provider in memoria, eseguirne il mapping a una query tramite ToInMemoryQuery. Per altre informazioni, vedere la documentazione del provider in memoria.