Tipi di entità senza chiaveKeyless Entity Types

Nota

Questa funzionalità è stata aggiunta in EF Core 2,1 sotto il nome dei tipi di query.This feature was added in EF Core 2.1 under the name of query types. In EF Core 3,0 il concetto è stato rinominato in tipi di entità senza chiave.In EF Core 3.0 the concept was renamed to keyless entity types.

Oltre ai normali tipi di entità, un modello di 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.In addition to regular entity types, an EF Core model can contain keyless entity types, which can be used to carry out database queries against data that doesn't contain key values.

Caratteristiche di tipi di entità autochiaveKeyless entity types characteristics

I tipi di entità autonome supportano molte delle stesse funzionalità di mapping dei normali tipi di entità, ad esempio il mapping di ereditarietà e le proprietà di navigazione.Keyless entity types support many of the same mapping capabilities as regular entity types, like inheritance mapping and navigation properties. In archivi relazionali, è possibile configurare le oggetti di database di destinazione e le colonne tramite metodi dell'API fluent o annotazioni dei dati.On relational stores, they can configure the target database objects and columns via fluent API methods or data annotations.

Tuttavia, sono diversi dai normali tipi di entità in quanto:However, they are different from regular entity types in that they:

  • Non è possibile definire una chiave.Cannot have a key defined.
  • Non vengono mai rilevate per le modifiche apportate in DbContext e pertanto non vengono mai inserite, aggiornate o eliminate nel database.Are never tracked for changes in the DbContext and therefore are never inserted, updated or deleted on the database.
  • Non vengono mai individuati dalla convenzione.Are never discovered by convention.
  • Supporta solo un subset di funzionalità di mapping di navigazione, in particolare:Only support a subset of navigation mapping capabilities, specifically:
    • Mai agiscono come entità finale principale di una relazione.They may never act as the principal end of a relationship.
    • Potrebbero non avere spostamenti sulle entità di proprietàThey may not have navigations to owned entities
    • Possono contenere solo proprietà di navigazione di riferimento che puntano a entità regolari.They can only contain reference navigation properties pointing to regular entities.
    • Le entità non possono contenere proprietà di navigazione per i tipi di entità autochiave.Entities cannot contain navigation properties to keyless entity types.
  • Deve essere configurato con .HasNoKey() chiamata al metodo.Need to be configured with .HasNoKey() method call.
  • Può essere mappato a una query di definizione.May be mapped to a defining query. Una query di definizione è una query dichiarata nel modello che funge da origine dati per un tipo di entità autonome.A defining query is a query declared in the model that acts as a data source for a keyless entity type.

Scenari di utilizzoUsage scenarios

Di seguito sono riportati alcuni degli scenari di utilizzo principali per i tipi di entità autochiave:Some of the main usage scenarios for keyless entity types are:

  • Fungendo da tipo restituito per le query SQL non elaborate.Serving as the return type for raw SQL queries.
  • Mapping a viste di database che non contengono una chiave primaria.Mapping to database views that do not contain a primary key.
  • Mapping a tabelle che non è definita una chiave primaria.Mapping to tables that do not have a primary key defined.
  • Mapping a query definite nel modello.Mapping to queries defined in the model.

Mapping agli oggetti di databaseMapping to database objects

Il mapping di un tipo di entità autochiave a un oggetto di database viene eseguito usando l'API ToTable o ToView Fluent.Mapping a keyless entity type to a database object is achieved using the ToTable or ToView fluent API. Dal punto di vista di EF Core, l'oggetto di database specificato in questo metodo è un vista, vale a dire che viene considerato come un'origine di query di sola lettura e non può essere la destinazione dell'aggiornamento, inserire o eliminare le operazioni.From the perspective of EF Core, the database object specified in this method is a view, meaning that it is treated as a read-only query source and cannot be the target of update, insert or delete operations. Tuttavia, ciò non significa che l'oggetto di database debba essere effettivamente una vista di database.However, this does not mean that the database object is actually required to be a database view. In alternativa, può essere una tabella di database che verrà considerata di sola lettura.It can alternatively be a database table that will be treated as read-only. Viceversa, per i tipi di entità regolari, EF Core presuppone che un oggetto di database specificato nel metodo ToTable possa essere considerato come una tabella, ovvero può essere utilizzato come origine della query, ma anche come destinazione da operazioni di aggiornamento, eliminazione e inserimento.Conversely, for regular entity types, EF Core assumes that a database object specified in the ToTable method can be treated as a table, meaning that it can be used as a query source but also targeted by update, delete and insert operations. In effetti, è possibile specificare il nome di una vista di database in ToTable e tutto dovrebbe funzionare senza problemi, purché la visualizzazione è configurata per essere aggiornabile nel database.In fact, you can specify the name of a database view in ToTable and everything should work fine as long as the view is configured to be updatable on the database.

Nota

ToView presuppone che l'oggetto esista già nel database e non venga creato dalle migrazioni.ToView assumes that the object already exists in the database and it won't be created by migrations.

EsempioExample

Nell'esempio seguente viene illustrato come utilizzare i tipi di entità autochiave per eseguire una query su una vista di database.The following example shows how to use keyless entity types to query a database view.

Suggerimento

È possibile visualizzare l'esempio di questo articolo in GitHub.You can view this article's sample on GitHub.

In primo luogo, definiamo un semplice modello di post di Blog e Post:First, we define a simple Blog and Post model:

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, viene definita una vista di database semplici che ci consentirà di eseguire una query il numero di post associati a ciascun blog:Next, we define a simple database view that will allow us to query the number of posts associated with each 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");

Successivamente, viene definita una classe che contenga il risultato della vista di database:Next, we define a class to hold the result from the database view:

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

Successivamente, si configura il tipo di entità autochiave in OnModelCreating usando l'API HasNoKey.Next, we configure the keyless entity type in OnModelCreating using the HasNoKey API. Si usa l'API di configurazione Fluent per configurare il mapping per il tipo di entità autochiave:We use fluent configuration API to configure the mapping for the keyless entity type:

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

Viene quindi configurata la DbContext per includere l'DbSet<T>:Next, we configure the DbContext to include the DbSet<T>:

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

Infine, è possibile eseguire una query la visualizzazione del database nella modalità standard:Finally, we can query the database view in the standard way:

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) che funge da radice per le query su questo tipo.Note we have also defined a context level query property (DbSet) to act as a root for queries against this type.