Razor Pages con Entity Framework Core in ASP.NET Core: esercitazione 1 di 8Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial 1 of 8

Di Tom Dykstra e Rick AndersonBy Tom Dykstra and Rick Anderson

Questo è il primo di una serie di esercitazioni che illustrano come usare Entity Framework (EF) Core in un'app ASP.NET Core Razor Pages .This is the first in a series of tutorials that show how to use Entity Framework (EF) Core in an ASP.NET Core Razor Pages app. Con queste esercitazioni viene creato un sito Web per una fittizia Contoso University.The tutorials build a web site for a fictional Contoso University. Il sito include funzionalità, come ad esempio l'ammissione di studenti, la creazione di corsi e le assegnazioni degli insegnati.The site includes functionality such as student admission, course creation, and instructor assignments.

Scaricare o visualizzare l'app completata.Download or view the completed app. Istruzioni per il download.Download instructions.

PrerequisitiPrerequisites

Motori di databaseDatabase engines

Le istruzioni per Visual Studio usano SQL Server Local DB, una versione di SQL Server Express eseguita solo in Windows.The Visual Studio instructions use SQL Server LocalDB, a version of SQL Server Express that runs only on Windows.

Le istruzioni per Visual Studio Code usano SQLite, un motore di database multipiattaforma.The Visual Studio Code instructions use SQLite, a cross-platform database engine.

Se si sceglie di usare SQLite, scaricare e installare uno strumento di terze parti per la gestione e la visualizzazione di un database SQLite, ad esempio DB Browser per SQLite.If you choose to use SQLite, download and install a third-party tool for managing and viewing a SQLite database, such as DB Browser for SQLite.

Risoluzione dei problemiTroubleshooting

Se si verifica un problema che non è possibile risolvere, confrontare il codice con il progetto completato.If you run into a problem you can't resolve, compare your code to the completed project. Un buon metodo per ottenere assistenza è quello di pubblicare una domanda in StackOverflow.com con il tag ASP.NET Core o il tag EF Core.A good way to get help is by posting a question to StackOverflow.com, using the ASP.NET Core tag or the EF Core tag.

App di esempioThe sample app

L'applicazione compilata in queste esercitazioni è il sito Web di base di un'università.The app built in these tutorials is a basic university web site. Gli utenti possono visualizzare e aggiornare le informazioni che riguardano studenti, corsi e insegnanti.Users can view and update student, course, and instructor information. Di seguito sono disponibili alcune schermate dell'esercitazione.Here are a few of the screens created in the tutorial.

Pagina Student Index (Indice degli studenti)

Pagina Students Edit (Modifica studenti)

Lo stile dell'interfaccia utente del sito è basato sui modelli di progetto predefiniti.The UI style of this site is based on the built-in project templates. L'obiettivo dell'esercitazione è quello di usare EF Core e non di personalizzare l'interfaccia utente.The tutorial's focus is on how to use EF Core, not how to customize the UI.

Seguire il collegamento nella parte superiore della pagina per ottenere il codice sorgente per il progetto completato.Follow the link at the top of the page to get the source code for the completed project. La cartella cu30 contiene il codice per la versione di ASP.NET Core 3.0 dell'esercitazione.The cu30 folder has the code for the ASP.NET Core 3.0 version of the tutorial. I file che riflettono lo stato del codice per le esercitazioni 1-7 si trovano nella cartella cu30snapshots.Files that reflect the state of the code for tutorials 1-7 can be found in the cu30snapshots folder.

Per eseguire l'app dopo il download del progetto completato:To run the app after downloading the completed project:

  • Eliminare i tre file e la cartella con SQLite nel nome.Delete three files and one folder that have SQLite in the name.

  • Compilare il progetto.Build the project.

  • Nella console di Gestione pacchetti eseguire il comando seguente:In Package Manager Console (PMC) run the following command:

    Update-Database
    
  • Eseguire il progetto per il seeding del database.Run the project to seed the database.

Creare il progetto di app WebCreate the web app project

  • Dal menu File di Visual Studio selezionare Nuovo > Progetto.From the Visual Studio File menu, select New > Project.
  • Selezionare Applicazione Web ASP.NET Core.Select ASP.NET Core Web Application.
  • Denominare il progetto ContosoUniversity.Name the project ContosoUniversity. È importante usare questo nome esatto, incluse le maiuscole, in modo che gli spazi dei nomi corrispondano quando il codice viene copiato e incollato.It's important to use this exact name including capitalization, so the namespaces match when code is copied and pasted.
  • Selezionare .NET Core e ASP.NET Core 3.0 nell'elenco a discesa, quindi selezionare Applicazione Web.Select .NET Core and ASP.NET Core 3.0 in the dropdowns, and then select Web Application.

Impostare lo stile del sitoSet up the site style

Per impostare l'intestazione, il piè di pagina e il menu del sito, aggiornare Pages/Shared/_Layout.cshtml:Set up the site header, footer, and menu by updating Pages/Shared/_Layout.cshtml:

  • Modificare tutte le occorrenze di "ContosoUniversity" in "Contoso University".Change each occurrence of "ContosoUniversity" to "Contoso University". Le occorrenze sono tre.There are three occurrences.

  • Eliminare le voci di menu Home e Privacy, quindi aggiungere le voci per About (Informazioni su), Students (Studenti), Courses (Corsi), Instructors (Insegnanti) e Departments (Dipartimenti).Delete the Home and Privacy menu entries, and add entries for About, Students, Courses, Instructors, and Departments.

Le modifiche vengono evidenziate.The changes are highlighted.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2019 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

In Pages/Index.cshtml sostituire il contenuto del file con il codice seguente. In questo modo il testo su ASP.NET sarà sostituito dal testo relativo a questa app:In Pages/Index.cshtml, replace the contents of the file with the following code to replace the text about ASP.NET Core with text about this app:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="row mb-auto">
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 mb-4 ">
                <p class="card-text">
                    Contoso University is a sample application that
                    demonstrates how to use Entity Framework Core in an
                    ASP.NET Core Razor Pages web app.
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column position-static">
                <p class="card-text mb-auto">
                    You can build the application by following the steps in a series of tutorials.
                </p>
                <p>
                    <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column">
                <p class="card-text mb-auto">
                    You can download the completed project from GitHub.
                </p>
                <p>
                    <a href="https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
                </p>
            </div>
        </div>
    </div>
</div>

Eseguire l'app per verificare che venga visualizzata la home page.Run the app to verify that the home page appears.

Modello di datiThe data model

Nelle sezioni seguenti viene descritto come creare un modello di dati:The following sections create a data model:

Diagramma modello di dati Course/Enrollment/Student (Corso/Iscrizione/Studente)

Uno studente può iscriversi a un numero qualsiasi di corsi e un corso può avere un numero qualsiasi di studenti iscritti.A student can enroll in any number of courses, and a course can have any number of students enrolled in it.

Entità Student (Studente)The Student entity

Diagramma entità Student (Studente)

  • Creare una cartella Models nella cartella del progetto.Create a Models folder in the project folder.

  • Creare Models/Student.cs con il codice seguente:Create Models/Student.cs with the following code:

    using System;
    using System.Collections.Generic;
    
    namespace ContosoUniversity.Models
    {
        public class Student
        {
            public int ID { get; set; }
            public string LastName { get; set; }
            public string FirstMidName { get; set; }
            public DateTime EnrollmentDate { get; set; }
    
            public ICollection<Enrollment> Enrollments { get; set; }
        }
    }
    

La proprietà ID diventa la colonna chiave primaria della tabella del database che corrisponde a questa classe.The ID property becomes the primary key column of the database table that corresponds to this class. Per impostazione predefinita, Entity Framework Core interpreta una proprietà denominata ID o classnameID come chiave primaria.By default, EF Core interprets a property that's named ID or classnameID as the primary key. Il nome alternativo riconosciuto automaticamente per la chiave primaria della classe Student è quindi StudentID.So the alternative automatically recognized name for the Student class primary key is StudentID.

La proprietà Enrollments rappresenta una proprietà di navigazione.The Enrollments property is a navigation property. Le proprietà di navigazione contengono altre entità correlate a questa entità.Navigation properties hold other entities that are related to this entity. In questo caso la proprietà Enrollments di un'entità Student contiene tutte le entità Enrollment correlate a tale studente.In this case, the Enrollments property of a Student entity holds all of the Enrollment entities that are related to that Student. Ad esempio, se una riga Student nel database presenta due righe Enrollment correlate, la proprietà di navigazione Enrollments contiene questi due entità Enrollment.For example, if a Student row in the database has two related Enrollment rows, the Enrollments navigation property contains those two Enrollment entities.

Nel database, una riga Enrollment è correlata a una riga Student se la relativa colonna StudentID contiene il valore ID dello studente.In the database, an Enrollment row is related to a Student row if its StudentID column contains the student's ID value. Si supponga, ad esempio, che una riga Student abbia ID=1.For example, suppose a Student row has ID=1. Le righe Enrollment correlate avranno StudentID = 1.Related Enrollment rows will have StudentID = 1. StudentID è una chiave esterna nella tabella Enrollment.StudentID is a foreign key in the Enrollment table.

La proprietà Enrollments è definita come ICollection<Enrollment> perché potrebbero essere presenti più entità Enrollment correlate.The Enrollments property is defined as ICollection<Enrollment> because there may be multiple related Enrollment entities. È possibile usare altri tipi di raccolta, ad esempio List<Enrollment> o HashSet<Enrollment>.You can use other collection types, such as List<Enrollment> or HashSet<Enrollment>. Se si specifica ICollection<Enrollment>, per impostazione predefinita Entity Framework Core crea una raccolta HashSet<Enrollment>.When ICollection<Enrollment> is used, EF Core creates a HashSet<Enrollment> collection by default.

Entità Enrollment (Iscrizione)The Enrollment entity

Diagramma entità Enrollment (Iscrizione)

Creare Models/Enrollment.cs con il codice seguente:Create Models/Enrollment.cs with the following code:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}

La proprietà EnrollmentID è la chiave primaria. Questa entità usa il modello classnameID anziché ID da solo.The EnrollmentID property is the primary key; this entity uses the classnameID pattern instead of ID by itself. Per un modello di dati di produzione, scegliere un modello e usarlo in modo coerente.For a production data model, choose one pattern and use it consistently. Questa esercitazione usa entrambi solo per illustrare che entrambi funzionano.This tutorial uses both just to illustrate that both work. L'uso di ID senza classname rende più semplice l'implementazione di alcuni tipi di modifiche al modello di dati.Using ID without classname makes it easier to implement some kinds of data model changes.

La proprietà Grade è un oggettoenum.The Grade property is an enum. Il punto interrogativo dopo la dichiarazione del tipo Grade indica che la proprietà Grade ammette i valori Null.The question mark after the Grade type declaration indicates that the Grade property is nullable. Un voto con valore Null è diverso da un voto con valore zero. Null significa che un voto è sconosciuto o non è stato ancora assegnato.A grade that's null is different from a zero grade—null means a grade isn't known or hasn't been assigned yet.

La proprietà StudentID è una chiave esterna e la proprietà di navigazione corrispondente è Student.The StudentID property is a foreign key, and the corresponding navigation property is Student. Un'entità Enrollment è associata a un'entità Student, pertanto la proprietà contiene un'unica entità Student.An Enrollment entity is associated with one Student entity, so the property contains a single Student entity.

La proprietà CourseID è una chiave esterna e la proprietà di navigazione corrispondente è Course.The CourseID property is a foreign key, and the corresponding navigation property is Course. Un'entità Enrollment è associata a un'entità Course.An Enrollment entity is associated with one Course entity.

Entity Framework Core interpreta una proprietà come chiave esterna se è denominata <navigation property name><primary key property name>.EF Core interprets a property as a foreign key if it's named <navigation property name><primary key property name>. Ad esempio, StudentID è la chiave esterna per la proprietà di navigazione Student, dato che la chiave primaria Student dell'entità è ID.For example,StudentID is the foreign key for the Student navigation property, since the Student entity's primary key is ID. Le proprietà di chiave esterna possono anche essere denominate <primary key property name>.Foreign key properties can also be named <primary key property name>. Ad esempio, CourseID poiché la chiave primaria Course dell'entità è CourseID.For example, CourseID since the Course entity's primary key is CourseID.

Entità Course (Corso)The Course entity

Diagramma entità Course (Corso)

Creare Models/Course.cs con il codice seguente:Create Models/Course.cs with the following code:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

La proprietà Enrollments rappresenta una proprietà di navigazione.The Enrollments property is a navigation property. È possibile correlare un'entità Course a un numero qualsiasi di entità Enrollment.A Course entity can be related to any number of Enrollment entities.

L'attributo DatabaseGenerated consente all'app di specificare la chiave primaria anziché chiedere al database di generarla.The DatabaseGenerated attribute allows the app to specify the primary key rather than having the database generate it.

Compilare il progetto per verificare che non siano presenti errori del compilatore.Build the project to validate that there are no compiler errors.

Scaffolding delle pagine StudentScaffold Student pages

In questa sezione si userà lo strumento di scaffolding di ASP.NET Core per generare:In this section, you use the ASP.NET Core scaffolding tool to generate:

  • Una classe contesto di EF Core.An EF Core context class. Il contesto è la classe principale che coordina le funzionalità di Entity Framework per un determinato modello di dati.The context is the main class that coordinates Entity Framework functionality for a given data model. Deriva dalla classe Microsoft.EntityFrameworkCore.DbContext.It derives from the Microsoft.EntityFrameworkCore.DbContext class.
  • Pagine Razor che gestiscono operazioni CRUD (creazione, lettura, aggiornamento ed eliminazione) per l'entità Student.Razor pages that handle Create, Read, Update, and Delete (CRUD) operations for the Student entity.
  • Creare una cartella Students nella cartella Pages.Create a Students folder in the Pages folder.
  • In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Pages/Students e quindi scegliere Aggiungi > Nuovo elemento di scaffolding.In Solution Explorer, right-click the Pages/Students folder and select Add > New Scaffolded Item.
  • Nella finestra di dialogo Aggiungi scaffolding selezionare Pagine Razor che usano Entity Framework (CRUD) > Aggiungi.In the Add Scaffold dialog, select Razor Pages using Entity Framework (CRUD) > ADD.
  • Nella finestra di dialogo Pagine Razor che usano Entity Framework (CRUD) :In the Add Razor Pages using Entity Framework (CRUD) dialog:
    • Nell'elenco a discesa Classe modello selezionare Student (ContosoUniversity.Models) .In the Model class drop-down, select Student (ContosoUniversity.Models).
    • Nella riga Classe contesto di dati selezionare il segno più + .In the Data context class row, select the + (plus) sign.
    • Modificare il nome del contesto di dati da ContosoUniversity.Models.ContosoUniversityContext a ContosoUniversity.Data.SchoolContext.Change the data context name from ContosoUniversity.Models.ContosoUniversityContext to ContosoUniversity.Data.SchoolContext.
    • Selezionare Aggiungi.Select Add.

Vengono installati automaticamente i pacchetti seguenti:The following packages are automatically installed:

  • Microsoft.VisualStudio.Web.CodeGeneration.Design
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.Extensions.Logging.Debug
  • Microsoft.EntityFrameworkCore.Tools

Se si riscontra un problema con il passaggio precedente, compilare il progetto e riprovare a eseguire il passaggio di scaffolding.If you have a problem with the preceding step, build the project and retry the scaffold step.

Il processo di scaffolding:The scaffolding process:

  • Crea pagine Razor nella cartella Pages/Students:Creates Razor pages in the Pages/Students folder:
    • Create.cshtml e Create.cshtml.csCreate.cshtml and Create.cshtml.cs
    • Delete.cshtml e Delete.cshtml.csDelete.cshtml and Delete.cshtml.cs
    • Details.cshtml e Details.cshtml.csDetails.cshtml and Details.cshtml.cs
    • Edit.cshtml e Edit.cshtml.csEdit.cshtml and Edit.cshtml.cs
    • Index.cshtml e Index.cshtml.csIndex.cshtml and Index.cshtml.cs
  • Crea Data/SchoolContext.cs.Creates Data/SchoolContext.cs.
  • Aggiunge il contesto all'inserimento delle dipendenze in Startup.cs.Adds the context to dependency injection in Startup.cs.
  • Aggiunge la stringa di connessione al database ad appsettings.json.Adds a database connection string to appsettings.json.

Stringa di connessione al databaseDatabase connection string

La stringa di connessione specifica SQL Server Local DB.The connection string specifies SQL Server LocalDB.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

Local DB è una versione leggera del motore di database di SQL Server Express appositamente pensato per lo sviluppo di app e non per la produzione.LocalDB is a lightweight version of the SQL Server Express Database Engine and is intended for app development, not production use. Per impostazione predefinita, Local DB crea file con estensione mdf nella directory C:/Users/<user>.By default, LocalDB creates .mdf files in the C:/Users/<user> directory.

Aggiornare la classe del contesto di databaseUpdate the database context class

La classe principale che coordina le funzionalità di EF Core per un determinato modello di dati è la classe del contesto di database.The main class that coordinates EF Core functionality for a given data model is the database context class. Il contesto è derivato da Microsoft.EntityFrameworkCore.DbContext.The context is derived from Microsoft.EntityFrameworkCore.DbContext. Il contesto specifica le entità incluse nel modello di dati.The context specifies which entities are included in the data model. In questo progetto la classe è denominata SchoolContext.In this project, the class is named SchoolContext.

Aggiornare SchoolContext.cs con il codice seguente:Update SchoolContext.cs with the following code:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;

namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext (DbContextOptions<SchoolContext> options)
            : base(options)
        {
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Course> Courses { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}

Il codice evidenziato crea una proprietà DbSet<TEntity> per ogni set di entità.The highlighted code creates a DbSet<TEntity> property for each entity set. Nella terminologia di Entity Framework Core:In EF Core terminology:

  • Un set di entità corrisponde in genere alla tabella di un database.An entity set typically corresponds to a database table.
  • Un'entità corrisponde a una riga nella tabella.An entity corresponds to a row in the table.

Dato che un set di entità contiene più entità, le proprietà DBSet devono essere nomi plurali.Since an entity set contains multiple entities, the DBSet properties should be plural names. Dato che lo strumento di scaffolding ha creato un DBSet Student, questo passaggio lo modifica nel plurale Students.Since the scaffolding tool created aStudent DBSet, this step changes it to plural Students.

Per fare in modo che il codice Razor Pages riconosca il nuovo nome del DBSet, sostituire globalmente _context.Student con _context.Students nell'intero progetto.To make the Razor Pages code match the new DBSet name, make a global change across the whole project of _context.Student to _context.Students. Sono presenti 8 occorrenze.There are 8 occurrences.

Compilare il progetto per verificare che non siano presenti errori di compilazione.Build the project to verify there are no compiler errors.

Startup.csStartup.cs

ASP.NET Core viene compilato tramite dependency injection.ASP.NET Core is built with dependency injection. I servizi, ad esempio il contesto di database di EF Core, vengono registrati con l'inserimento delle dipendenze durante l'avvio dell'applicazione.Services (such as the EF Core database context) are registered with dependency injection during application startup. Questi servizi vengono quindi offerti ai componenti per cui sono necessari (ad esempio Razor Pages) tramite i parametri del costruttore.Components that require these services (such as Razor Pages) are provided these services via constructor parameters. Più avanti nell'esercitazione viene illustrato il codice del costruttore che ottiene un'istanza del contesto di database.The constructor code that gets a database context instance is shown later in the tutorial.

Lo strumento di scaffolding ha registrato automaticamente la classe di contesto nel contenitore di inserimento delle dipendenze.The scaffolding tool automatically registered the context class with the dependency injection container.

  • In ConfigureServices le righe evidenziate sono state aggiunte dallo scaffolder:In ConfigureServices, the highlighted lines were added by the scaffolder:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    
        services.AddDbContext<SchoolContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
    }
    

Il nome della stringa di connessione viene passato al contesto chiamando un metodo in un oggetto DbContextOptions.The name of the connection string is passed in to the context by calling a method on a DbContextOptions object. Per lo sviluppo locale, il sistema di configurazione di ASP.NET Core legge la stringa di connessione dal file appsettings.json.For local development, the ASP.NET Core configuration system reads the connection string from the appsettings.json file.

Creare il databaseCreate the database

Aggiornare Program.cs per creare il database se non esiste:Update Program.cs to create the database if it doesn't exist:

using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            CreateDbIfNotExists(host);

            host.Run();
        }

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    context.Database.EnsureCreated();
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Il metodo EnsureCreated non esegue alcuna azione se esiste un database per il contesto.The EnsureCreated method takes no action if a database for the context exists. Se non esiste alcun database, vengono creati il database e lo schema.If no database exists, it creates the database and schema. EnsureCreated abilita il flusso di lavoro seguente per la gestione delle modifiche al modello di dati:EnsureCreated enables the following workflow for handling data model changes:

  • Eliminare il database.Delete the database. Tutti i dati esistenti andranno perduti.Any existing data is lost.
  • Modificare il modello di dati.Change the data model. Ad esempio, aggiungere un campo EmailAddress.For example, add an EmailAddress field.
  • Eseguire l'app.Run the app.
  • EnsureCreated crea un database con il nuovo schema.EnsureCreated creates a database with the new schema.

Questo flusso di lavoro funziona correttamente nelle fasi iniziali dello sviluppo quando lo schema è in rapida evoluzione, purché non sia necessario conservare i dati.This workflow works well early in development when the schema is rapidly evolving, as long as you don't need to preserve data. La situazione è diversa quando è necessario mantenere i dati immessi nel database.The situation is different when data that has been entered into the database needs to be preserved. In tal caso, usare le migrazioni.When that is the case, use migrations.

Più avanti nella serie di esercitazioni si vedrà come eliminare il database creato da EnsureCreated e usare invece le migrazioni.Later in the tutorial series, you delete the database that was created by EnsureCreated and use migrations instead. Non è possibile aggiornare un database creato da EnsureCreated usando le migrazioni.A database that is created by EnsureCreated can't be updated by using migrations.

Eseguire il test dell'appTest the app

  • Eseguire l'app.Run the app.
  • Selezionare il collegamento Students (Studenti) e quindi Crea nuovo.Select the Students link and then Create New.
  • Eseguire il test dei collegamenti Edit (Modifica), Details (Dettagli) e Delete (Elimina).Test the Edit, Details, and Delete links.

Specificare il valore di inizializzazione del databaseSeed the database

Il metodo EnsureCreated crea un database vuoto.The EnsureCreated method creates an empty database. In questa sezione viene aggiunto il codice che popola il database con dati di test.This section adds code that populates the database with test data.

Creare Data/DbInitializer.cs con il codice seguente:Create Data/DbInitializer.cs with the following code:

using ContosoUniversity.Data;
using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            context.Database.EnsureCreated();

            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
                new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
            };
            foreach (Student s in students)
            {
                context.Students.Add(s);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
                new Course{CourseID=1050,Title="Chemistry",Credits=3},
                new Course{CourseID=4022,Title="Microeconomics",Credits=3},
                new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
                new Course{CourseID=1045,Title="Calculus",Credits=4},
                new Course{CourseID=3141,Title="Trigonometry",Credits=4},
                new Course{CourseID=2021,Title="Composition",Credits=3},
                new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Courses.Add(c);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
                new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
                new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
                new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
                new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
                new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
                new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
                new Enrollment{StudentID=3,CourseID=1050},
                new Enrollment{StudentID=4,CourseID=1050},
                new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
                new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
                new Enrollment{StudentID=6,CourseID=1045},
                new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollments.Add(e);
            }
            context.SaveChanges();
        }
    }
}

Il codice controlla se esistono studenti nel database.The code checks if there are any students in the database. Se non sono presenti studenti, aggiunge i dati di test al database.If there are no students, it adds test data to the database. I dati di test vengono creati in matrici anziché in raccolte List<T> per ottimizzare le prestazioni.It creates the test data in arrays rather than List<T> collections to optimize performance.

  • In Program.cs sostituire la chiamata di EnsureCreated con una chiamata di DbInitializer.Initialize:In Program.cs, replace the EnsureCreated call with a DbInitializer.Initialize call:

    // context.Database.EnsureCreated();
    DbInitializer.Initialize(context);
    

Arrestare l'app se è in esecuzione ed eseguire il comando seguente nella console di Gestione pacchetti:Stop the app if it's running, and run the following command in the Package Manager Console (PMC):

Drop-Database
  • Riavviare l'app.Restart the app.

  • Selezionare la pagina Students per visualizzare i dati di seeding.Select the Students page to see the seeded data.

Visualizzare il databaseView the database

  • Aprire Esplora oggetti di SQL Server dal menu Visualizza in Visual Studio.Open SQL Server Object Explorer (SSOX) from the View menu in Visual Studio.
  • In Esplora oggetti di SQL Server selezionare (localdb)\MSSQLLocalDB > Database > SchoolContext-{GUID} .In SSOX, select (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Il nome del database viene generato dal nome del contesto specificato in precedenza con l'aggiunta di un trattino e un GUID.The database name is generated from the context name you provided earlier plus a dash and a GUID.
  • Espandere il nodo Tabelle.Expand the Tables node.
  • Fare clic con il pulsante destro del mouse sulla tabella Student (Studente) e fare clic su Visualizza dati per visualizzare le colonne create e le righe inserite nella tabella.Right-click the Student table and click View Data to see the columns created and the rows inserted into the table.
  • Fare clic con il pulsante destro del mouse sulla tabella Student e scegliere Visualizza codice per vedere il mapping tra il modello Student e lo schema della tabella Student.Right-click the Student table and click View Code to see how the Student model maps to the Student table schema.

Codice asincronoAsynchronous code

La programmazione asincrona è la modalità predefinita per ASP.NET Core ed Entity Framework Core.Asynchronous programming is the default mode for ASP.NET Core and EF Core.

Per un server Web è disponibile un numero limitato di thread e in situazioni di carico elevato tutti i thread disponibili potrebbero essere in uso.A web server has a limited number of threads available, and in high load situations all of the available threads might be in use. In queste circostanze il server non può elaborare nuove richieste finché i thread non saranno liberi.When that happens, the server can't process new requests until the threads are freed up. Con il codice sincrono, può succedere che molti thread siano vincolati nonostante in quel momento non stiano eseguendo alcuna operazione. Rimangono tuttavia in attesa che l'operazione I/O sia completata.With synchronous code, many threads may be tied up while they aren't actually doing any work because they're waiting for I/O to complete. Con il codice asincrono, se un processo è in attesa del completamento dell'operazione I/O, il thread viene liberato e il server lo può usare per l'elaborazione di altre richieste.With asynchronous code, when a process is waiting for I/O to complete, its thread is freed up for the server to use for processing other requests. Di conseguenza, il codice asincrono consente un uso più efficiente delle risorse del server e il server può gestire una maggiore quantità di traffico senza ritardi.As a result, asynchronous code enables server resources to be used more efficiently, and the server can handle more traffic without delays.

Il codice asincrono comporta un minimo sovraccarico in fase di esecuzione.Asynchronous code does introduce a small amount of overhead at run time. In caso di traffico ridotto, il calo delle prestazioni è irrilevante, mentre nelle situazioni di traffico elevato, è essenziale ottimizzare le prestazioni potenziali.For low traffic situations, the performance hit is negligible, while for high traffic situations, the potential performance improvement is substantial.

Nel codice seguente la parola chiave async, il valore restituito Task<T>, la parola chiave await e il metodo ToListAsync consentono di eseguire il codice in modo asincrono.In the following code, the async keyword, Task<T> return value, await keyword, and ToListAsync method make the code execute asynchronously.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • La parola chiave async indica al compilatore di eseguire le operazioni seguenti:The async keyword tells the compiler to:
    • Generare callback per parti del corpo del metodo.Generate callbacks for parts of the method body.
    • Creare l'oggetto Task restituito.Create the Task object that's returned.
  • Il tipo restituito Task<T> rappresenta il lavoro in corso.The Task<T> return type represents ongoing work.
  • La parola chiave await indica al compilatore di suddividere il metodo in due parti.The await keyword causes the compiler to split the method into two parts. La prima parte termina con l'operazione avviata in modo asincrono.The first part ends with the operation that's started asynchronously. La seconda parte viene inserita in un metodo di callback che viene chiamato al termine dell'operazione.The second part is put into a callback method that's called when the operation completes.
  • ToListAsync è la versione asincrona del metodo di estensione ToList.ToListAsync is the asynchronous version of the ToList extension method.

Alcuni aspetti da considerare quando si scrive codice asincrono usato da Entity Framework Core:Some things to be aware of when writing asynchronous code that uses EF Core:

  • Solo le istruzioni che generano query o comandi da inviare al database vengono eseguite in modo asincrono,Only statements that cause queries or commands to be sent to the database are executed asynchronously. Sono incluse ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync e SaveChangesAsync.That includes ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, and SaveChangesAsync. Non sono incluse le istruzioni che modificano solo un oggetto IQueryable, ad esempio var students = context.Students.Where(s => s.LastName == "Davolio").It doesn't include statements that just change an IQueryable, such as var students = context.Students.Where(s => s.LastName == "Davolio").
  • Un contesto di Entity Framework Core non è thread-safe. Non tentare di eseguire più operazioni parallelamente.An EF Core context isn't thread safe: don't try to do multiple operations in parallel.
  • Per sfruttare i vantaggi del codice asincrono in termini di prestazioni, verificare che i pacchetti della libreria impiegati, ad esempio per il paging, usino la modalità asincrona per chiamare i metodi di EF Core che inviano query al database.To take advantage of the performance benefits of async code, verify that library packages (such as for paging) use async if they call EF Core methods that send queries to the database.

Per altre informazioni sulla programmazione asincrona in .NET, vedere Panoramica della programmazione asincrona e Programmazione asincrona con async e await.For more information about asynchronous programming in .NET, see Async Overview and Asynchronous programming with async and await.

Passaggi successiviNext steps

L'app Web di esempio di Contoso University illustra come creare un'app ASP.NET Core di Razor Pages con Entity Framework (EF) Core.The Contoso University sample web app demonstrates how to create an ASP.NET Core Razor Pages app using Entity Framework (EF) Core.

L'app di esempio è un sito Web per una fittizia Contoso University.The sample app is a web site for a fictional Contoso University. Include funzionalità, come ad esempio l'ammissione di studenti, la creazione di corsi e le assegnazioni di insegnati.It includes functionality such as student admission, course creation, and instructor assignments. Questa pagina è il prima di una serie di esercitazioni che illustrano come compilare l'app di esempio di Contoso University.This page is the first in a series of tutorials that explain how to build the Contoso University sample app.

Scaricare o visualizzare l'app completata.Download or view the completed app. Istruzioni per il download.Download instructions.

PrerequisitiPrerequisites

Visual Studio 2019 con i carichi di lavoro seguenti:Visual Studio 2019 with the following workloads:

  • Sviluppo ASP.NET e WebASP.NET and web development
  • Sviluppo multipiattaforma .NET Core.NET Core cross-platform development

Conoscenza di Razor Pages.Familiarity with Razor Pages. Prima di iniziare questa serie, i programmatori non esperti dovranno completare l'introduzione a Razor Pages.New programmers should complete Get started with Razor Pages before starting this series.

Risoluzione dei problemiTroubleshooting

Se si verifica un problema che non si sa come risolvere, è generalmente possibile trovare la soluzione confrontando il codice con il progetto completato.If you run into a problem you can't resolve, you can generally find the solution by comparing your code to the completed project. Un buon metodo per ottenere assistenza è quello di pubblicare una domanda in StackOverflow.com per ASP.NET Core o EF Core.A good way to get help is by posting a question to StackOverflow.com for ASP.NET Core or EF Core.

App Web di Contoso UniversityThe Contoso University web app

L'applicazione compilata in queste esercitazioni è il sito Web di base di un'università.The app built in these tutorials is a basic university web site.

Gli utenti possono visualizzare e aggiornare le informazioni che riguardano studenti, corsi e insegnanti.Users can view and update student, course, and instructor information. Di seguito sono disponibili alcune schermate dell'esercitazione.Here are a few of the screens created in the tutorial.

Pagina Student Index (Indice degli studenti)

Pagina Students Edit (Modifica studenti)

Lo stile dell'interfaccia utente del sito è simile a quanto è stato generato tramite i modelli predefiniti.The UI style of this site is close to what's generated by the built-in templates. L'esercitazione è incentrata su Entity Framework Core con Razor Pages e non sull'interfaccia utente.The tutorial focus is on EF Core with Razor Pages, not the UI.

Creare l'app Web di Razor Pages ContosoUniversityCreate the ContosoUniversity Razor Pages web app

  • Dal menu File di Visual Studio selezionare Nuovo > Progetto.From the Visual Studio File menu, select New > Project.
  • Creare una nuova applicazione Web ASP.NET Core.Create a new ASP.NET Core Web Application. Denominare il progetto ContosoUniversity.Name the project ContosoUniversity. È importante denominare il progetto ContosoUniversity in modo che gli spazi dei nomi corrispondano quando il codice viene copiato/incollato.It's important to name the project ContosoUniversity so the namespaces match when code is copy/pasted.
  • Selezionare ASP.NET Core 2.1 nell'elenco a discesa, quindi selezionare Applicazione Web.Select ASP.NET Core 2.1 in the dropdown, and then select Web Application.

Per le immagini dei passaggi precedenti, vedere Creare un'app Web Razor.For images of the preceding steps, see Create a Razor web app. Eseguire l'app.Run the app.

Impostare lo stile del sitoSet up the site style

Con alcune modifiche è possibile impostare il menu del sito, il layout e la home page.A few changes set up the site menu, layout, and home page. Aggiornare Pages/Shared/_Layout.cshtml con le modifiche seguenti:Update Pages/Shared/_Layout.cshtml with the following changes:

  • Modificare tutte le occorrenze di "ContosoUniversity" in "Contoso University".Change each occurrence of "ContosoUniversity" to "Contoso University". Le occorrenze sono tre.There are three occurrences.

  • Aggiungere le voci di menu per Students (Studenti), Courses (Corsi), Instructors (Insegnanti) e Departments (Dipartimenti) ed eliminare la voce di menu Contact (Contatto).Add menu entries for Students, Courses, Instructors, and Departments, and delete the Contact menu entry.

Le modifiche vengono evidenziate.The changes are highlighted. Non viene visualizzato l'intero markup.(All the markup is not displayed.)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] : Contoso University</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-page="/Index" class="navbar-brand">Contoso University</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-page="/Index">Home</a></li>
                    <li><a asp-page="/About">About</a></li>
                    <li><a asp-page="/Students/Index">Students</a></li>
                    <li><a asp-page="/Courses/Index">Courses</a></li>
                    <li><a asp-page="/Instructors/Index">Instructors</a></li>
                    <li><a asp-page="/Departments/Index">Departments</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <partial name="_CookieConsentPartial" />

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 : Contoso University</p>
        </footer>
    </div>

    @*Remaining markup not shown for brevity.*@

In Pages/Index.cshtml sostituire il contenuto del file con il codice seguente. In questo modo il testo su ASP.NET e MVC sarà sostituito dal testo relativo a questa app:In Pages/Index.cshtml, replace the contents of the file with the following code to replace the text about ASP.NET and MVC with text about this app:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core Razor Pages web app.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p>
            <a class="btn btn-default"
               href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro">
                See the tutorial &raquo;
            </a>
        </p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p>
            <a class="btn btn-default"
               href="https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/data/ef-rp/intro/samples/">
                See project source code &raquo;
            </a>
        </p>
    </div>
</div>

Creare il modello di datiCreate the data model

Creare le classi delle entità per l'app di Contoso University.Create entity classes for the Contoso University app. Iniziare con le tre entità seguenti:Start with the following three entities:

Diagramma modello di dati Course/Enrollment/Student (Corso/Iscrizione/Studente)

Esiste una relazione uno-a-molti tra le entità Student e Enrollment.There's a one-to-many relationship between Student and Enrollment entities. Esiste una relazione uno-a-molti tra le entità Course e Enrollment.There's a one-to-many relationship between Course and Enrollment entities. Uno studente può iscriversi a un numero qualsiasi di corsi.A student can enroll in any number of courses. Un corso può avere un numero qualsiasi di studenti iscritti.A course can have any number of students enrolled in it.

Nelle sezioni seguenti viene creata una classe per ognuna di queste entità.In the following sections, a class for each one of these entities is created.

Entità Student (Studente)The Student entity

Diagramma entità Student (Studente)

Creare una cartella Models (Modelli).Create a Models folder. Nella cartella Models (Modelli) creare un file di classe denominato Student.cs con il codice seguente:In the Models folder, create a class file named Student.cs with the following code:

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

La proprietà ID diventa la colonna di chiave primaria della tabella di database (DB) che corrisponde a questa classe.The ID property becomes the primary key column of the database (DB) table that corresponds to this class. Per impostazione predefinita, Entity Framework Core interpreta una proprietà denominata ID o classnameID come chiave primaria.By default, EF Core interprets a property that's named ID or classnameID as the primary key. In classnameID classname è il nome della classe.In classnameID, classname is the name of the class. La chiave primaria alternativa riconosciuta automaticamente è StudentID nell'esempio precedente.The alternative automatically recognized primary key is StudentID in the preceding example.

La proprietà Enrollments rappresenta una proprietà di navigazione.The Enrollments property is a navigation property. Le proprietà di navigazione si collegano ad altre entità correlate a questa entità.Navigation properties link to other entities that are related to this entity. In questo caso la proprietà Enrollments di Student entity contiene tutte le entità Enrollment correlate a Student.In this case, the Enrollments property of a Student entity holds all of the Enrollment entities that are related to that Student. Ad esempio, se una riga Student (Studente) nella database presenta due righe Enrollment (Iscrizione) correlate, la proprietà di navigazione Enrollments contiene questi due entità Enrollment.For example, if a Student row in the DB has two related Enrollment rows, the Enrollments navigation property contains those two Enrollment entities. Una riga Enrollment correlata è una riga che contiene il valore della chiave primaria dello studente nella colonna StudentID.A related Enrollment row is a row that contains that student's primary key value in the StudentID column. Si supponga ad esempio che per lo studente con ID = 1 siano presenti due righe nella tabella Enrollment.For example, suppose the student with ID=1 has two rows in the Enrollment table. La tabella Enrollment contiene due righe con StudentID = 1.The Enrollment table has two rows with StudentID = 1. StudentID è una chiave esterna nella tabella Enrollment che specifica lo studente nella tabella Student.StudentID is a foreign key in the Enrollment table that specifies the student in the Student table.

Se una proprietà di navigazione può contenere più entità, deve essere un tipo elenco, ad esempio ICollection<T>.If a navigation property can hold multiple entities, the navigation property must be a list type, such as ICollection<T>. È possibile specificare ICollection<T> o un tipo, ad esempio List<T> o HashSet<T>.ICollection<T> can be specified, or a type such as List<T> or HashSet<T>. Se si specifica ICollection<T>, per impostazione predefinita Entity Framework Core crea una raccolta HashSet<T>.When ICollection<T> is used, EF Core creates a HashSet<T> collection by default. Le proprietà di navigazione che contengono più entità provengono da relazioni molti-a-molti e uno-a-molti.Navigation properties that hold multiple entities come from many-to-many and one-to-many relationships.

Entità Enrollment (Iscrizione)The Enrollment entity

Diagramma entità Enrollment (Iscrizione)

Nella cartella Models (Modelli) creare un file Enrollment.cs con il codice seguente:In the Models folder, create Enrollment.cs with the following code:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}

La proprietà EnrollmentID è la chiave primaria.The EnrollmentID property is the primary key. Questa entità usa il criterio classnameID anziché ID come l'entità Student.This entity uses the classnameID pattern instead of ID like the Student entity. In genere gli sviluppatori scelgono un criterio che usano poi in tutto il modello di dati.Typically developers choose one pattern and use it throughout the data model. In un'esercitazione successiva viene illustrato l'uso di ID senza classname. In questo modo si semplifica l'implementazione dell'ereditarietà nel modello di dati.In a later tutorial, using ID without classname is shown to make it easier to implement inheritance in the data model.

La proprietà Grade è un oggettoenum.The Grade property is an enum. Il punto interrogativo dopo la dichiarazione del tipo Grade indica che la proprietà Grade ammette i valori Null.The question mark after the Grade type declaration indicates that the Grade property is nullable. Un voto il cui valore è Null è diverso da un voto con valore zero. Null significa che un voto è sconosciuto o non è stato ancora assegnato.A grade that's null is different from a zero grade -- null means a grade isn't known or hasn't been assigned yet.

La proprietà StudentID è una chiave esterna e la proprietà di navigazione corrispondente è Student.The StudentID property is a foreign key, and the corresponding navigation property is Student. Un'entità Enrollment è associata a un'entità Student, pertanto la proprietà contiene un'unica entità Student.An Enrollment entity is associated with one Student entity, so the property contains a single Student entity. L'entità Student si differenzia dalla proprietà di navigazione Student.Enrollments che contiene più entità Enrollment.The Student entity differs from the Student.Enrollments navigation property, which contains multiple Enrollment entities.

La proprietà CourseID è una chiave esterna e la proprietà di navigazione corrispondente è Course.The CourseID property is a foreign key, and the corresponding navigation property is Course. Un'entità Enrollment è associata a un'entità Course.An Enrollment entity is associated with one Course entity.

Entity Framework Core interpreta una proprietà come chiave esterna se è denominata <navigation property name><primary key property name>.EF Core interprets a property as a foreign key if it's named <navigation property name><primary key property name>. Ad esempio, StudentID per la proprietà di navigazione Student, poiché la chiave primaria Student dell'entità è ID.For example,StudentID for the Student navigation property, since the Student entity's primary key is ID. Le proprietà di chiave esterna possono anche essere denominate <primary key property name>.Foreign key properties can also be named <primary key property name>. Ad esempio, CourseID poiché la chiave primaria Course dell'entità è CourseID.For example, CourseID since the Course entity's primary key is CourseID.

Entità Course (Corso)The Course entity

Diagramma entità Course (Corso)

Nella cartella Models (Modelli) creare un file Course.cs con il codice seguente:In the Models folder, create Course.cs with the following code:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

La proprietà Enrollments rappresenta una proprietà di navigazione.The Enrollments property is a navigation property. È possibile correlare un'entità Course a un numero qualsiasi di entità Enrollment.A Course entity can be related to any number of Enrollment entities.

L'attributo DatabaseGenerated consente all'app di specificare la chiave primaria anziché chiedere al database di generarla.The DatabaseGenerated attribute allows the app to specify the primary key rather than having the DB generate it.

Eseguire lo scaffolding del modello Student (Studente)Scaffold the student model

In questa sezione viene eseguito lo scaffolding del modello Student (Studente).In this section, the student model is scaffolded. Lo strumento di scaffolding crea quindi le pagine per le operazioni CRUD (creazione, lettura, aggiornamento ed eliminazione) per il modello Student (Studente).That is, the scaffolding tool produces pages for Create, Read, Update, and Delete (CRUD) operations for the student model.

  • Compilare il progetto.Build the project.
  • Creare la cartella Pages/Students.Create the Pages/Students folder.
  • In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Pages/Students > Aggiungi > Nuovo elemento di scaffolding.In Solution Explorer, right click on the Pages/Students folder > Add > New Scaffolded Item.
  • Nella finestra di dialogo Aggiungi scaffolding selezionare Pagine Razor che usano Entity Framework (CRUD) > Aggiungi.In the Add Scaffold dialog, select Razor Pages using Entity Framework (CRUD) > ADD.

Completare la finestra di dialogo Pagine Razor che usano Entity Framework (CRUD) :Complete the Add Razor Pages using Entity Framework (CRUD) dialog:

  • Nell'elenco a discesa Classe modello selezionare Student (ContosoUniversity.Models) .In the Model class drop-down, select Student (ContosoUniversity.Models).
  • Nella riga Classe contesto di dati selezionare il segno + (più) e modificare il nome generato in ContosoUniversity.Models.SchoolContext.In the Data context class row, select the + (plus) sign and change the generated name to ContosoUniversity.Models.SchoolContext.
  • Nell'elenco a discesa Classe contesto di dati selezionare ContosoUniversity.Models.SchoolContext.In the Data context class drop-down, select ContosoUniversity.Models.SchoolContext
  • Selezionare Aggiungi.Select Add.

Finestra di dialogo CRUD

Vedere Eseguire lo scaffolding del modello di filmato se si riscontrano problemi con il passaggio precedente.See Scaffold the movie model if you have a problem with the preceding step.

Il processo di scaffolding ha creato e modificato i file seguenti:The scaffold process created and changed the following files:

File creatiFiles created

  • Pagine Create (Crea), Delete (Elimina), Details (Dettagli), Edit (Modifica) e Index (Indice) di Pages/Students.Pages/Students Create, Delete, Details, Edit, Index.
  • Data/SchoolContext.csData/SchoolContext.cs

Aggiornamenti dei fileFile updates

  • Startup.cs : le modifiche a questo file sono descritte in dettaglio nella sezione successiva.Startup.cs : Changes to this file are detailed in the next section.
  • appsettings.json : è stata aggiunta la stringa di connessione usata per connettersi a un database locale.appsettings.json : The connection string used to connect to a local database is added.

Esaminare il contesto registrato con l'inserimento di dipendenzeExamine the context registered with dependency injection

ASP.NET Core viene compilato tramite dependency injection.ASP.NET Core is built with dependency injection. I servizi, ad esempio il contesto di database di Entity Framework Core, vengono registrati tramite dependency injection durante l'avvio dell'applicazione.Services (such as the EF Core DB context) are registered with dependency injection during application startup. Questi servizi vengono quindi offerti ai componenti per cui sono necessari (ad esempio Razor Pages) tramite i parametri del costruttore.Components that require these services (such as Razor Pages) are provided these services via constructor parameters. Più avanti nell'esercitazione viene illustrato il codice del costruttore che ottiene un'istanza del contesto di database.The constructor code that gets a db context instance is shown later in the tutorial.

Lo strumento di scaffolding ha creato automaticamente un contesto del database e lo ha registrato con il contenitore di inserimento delle dipendenze.The scaffolding tool automatically created a DB Context and registered it with the dependency injection container.

Esaminare il metodo ConfigureServices in Startup.cs.Examine the ConfigureServices method in Startup.cs. La riga evidenziata è stata aggiunta dallo scaffolder:The highlighted line was added by the scaffolder:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for 
        //non -essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddDbContext<SchoolContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
}

Il nome della stringa di connessione viene passato al contesto chiamando un metodo in un oggetto DbContextOptions.The name of the connection string is passed in to the context by calling a method on a DbContextOptions object. Per lo sviluppo locale, il sistema di configurazione di ASP.NET Core legge la stringa di connessione dal file appsettings.json.For local development, the ASP.NET Core configuration system reads the connection string from the appsettings.json file.

Aggiornare il metodo MainUpdate main

In Program.cs modificare il metodo Main per eseguire le operazioni seguenti:In Program.cs, modify the Main method to do the following:

  • Ottenere un'istanza del contesto di database dal contenitore di inserimento delle dipendenze.Get a DB context instance from the dependency injection container.
  • Chiamare EnsureCreated.Call the EnsureCreated.
  • Eliminare il contesto dopo che il metodo EnsureCreated è stato completato.Dispose the context when the EnsureCreated method completes.

Il codice seguente illustra il file Program.cs aggiornato.The following code shows the updated Program.cs file.

using ContosoUniversity.Models;                   // SchoolContext
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;   // CreateScope
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    context.Database.EnsureCreated();
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

EnsureCreated assicura che esista il database per il contesto.EnsureCreated ensures that the database for the context exists. Se esiste, non viene eseguita alcuna azione.If it exists, no action is taken. Se non esiste, vengono creati il database e tutti i relativi schemi.If it does not exist, then the database and all its schema are created. EnsureCreated non usa le migrazioni per creare il database.EnsureCreated does not use migrations to create the database. Un database creato con EnsureCreated non potrà essere aggiornato successivamente usando le migrazioni.A database that is created with EnsureCreated cannot be later updated using migrations.

EnsureCreated viene chiamato all'avvio dell'app e consente il flusso di lavoro seguente:EnsureCreated is called on app start, which allows the following work flow:

  • Eliminare il database.Delete the DB.
  • Modificare lo schema di database, ad esempio, aggiungere un campo EmailAddress.Change the DB schema (for example, add an EmailAddress field).
  • Eseguire l'app.Run the app.
  • EnsureCreated crea un database con la colonna EmailAddress.EnsureCreated creates a DB with theEmailAddress column.

EnsureCreated è utile nelle prime fasi di sviluppo quando lo schema è in rapida evoluzione.EnsureCreated is convenient early in development when the schema is rapidly evolving. Più avanti nell'esercitazione il database verrà eliminato e si useranno le migrazioni.Later in the tutorial the DB is deleted and migrations are used.

Eseguire il test dell'appTest the app

Eseguire l'app e accettare l'informativa sui cookie.Run the app and accept the cookie policy. Questa app non memorizza informazioni personali.This app doesn't keep personal information. È possibile consultare l'informativa sui cookie in Supporto per il Regolamento generale sulla protezione dei dati (GDPR) dell'Unione Europea.You can read about the cookie policy at EU General Data Protection Regulation (GDPR) support.

  • Selezionare il collegamento Students (Studenti) e quindi Crea nuovo.Select the Students link and then Create New.
  • Eseguire il test dei collegamenti Edit (Modifica), Details (Dettagli) e Delete (Elimina).Test the Edit, Details, and Delete links.

Esaminare il contesto di database SchoolContextExamine the SchoolContext DB context

La classe principale che coordina le funzionalità di Entity Framework Core per un determinato modello di dati è la classe del contesto di database.The main class that coordinates EF Core functionality for a given data model is the DB context class. Il contesto dei dati è derivato da Microsoft.EntityFrameworkCore.DbContext.The data context is derived from Microsoft.EntityFrameworkCore.DbContext. Il contesto dei dati specifica le entità incluse nel modello di dati.The data context specifies which entities are included in the data model. In questo progetto la classe è denominata SchoolContext.In this project, the class is named SchoolContext.

Aggiornare SchoolContext.cs con il codice seguente:Update SchoolContext.cs with the following code:

using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Models
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options)
            : base(options)
        {
        }

        public DbSet<Student> Student { get; set; }
        public DbSet<Enrollment> Enrollment { get; set; }
        public DbSet<Course> Course { get; set; }
    }
}

Il codice evidenziato crea una proprietà DbSet<TEntity> per ogni set di entità.The highlighted code creates a DbSet<TEntity> property for each entity set. Nella terminologia di Entity Framework Core:In EF Core terminology:

  • Nella terminologia di Entity Framework, un set di entità corrisponde in genere alla tabella di un database.An entity set typically corresponds to a DB table.
  • Un'entità corrisponde a una riga nella tabella.An entity corresponds to a row in the table.

DbSet<Enrollment> e DbSet<Course> potrebbero essere omessi.DbSet<Enrollment> and DbSet<Course> could be omitted. Core Entity Framework le include in modo implicito perché l'entità Student fa riferimento all'entità Enrollment e l'entità Enrollment fa riferimento all'entità Course.EF Core includes them implicitly because the Student entity references the Enrollment entity, and the Enrollment entity references the Course entity. Per questa esercitazione, mantenere DbSet<Enrollment> e DbSet<Course> in SchoolContext.For this tutorial, keep DbSet<Enrollment> and DbSet<Course> in the SchoolContext.

LocalDB di SQL Server ExpressSQL Server Express LocalDB

La stringa di connessione specifica SQL Server Local DB.The connection string specifies SQL Server LocalDB. Local DB è una versione leggera del motore di database di SQL Server Express appositamente pensato per lo sviluppo di app e non per la produzione.LocalDB is a lightweight version of the SQL Server Express Database Engine and is intended for app development, not production use. Local DB viene avviato su richiesta ed eseguito in modalità utente; non richiede quindi una configurazione complessa.LocalDB starts on demand and runs in user mode, so there's no complex configuration. Per impostazione predefinita, Local DB crea file di database con estensione mdf nella directory C:/Users/<user>.By default, LocalDB creates .mdf DB files in the C:/Users/<user> directory.

Aggiungere il codice per inizializzare il database con dati di testAdd code to initialize the DB with test data

Entity Framework Core crea un database vuoto.EF Core creates an empty DB. In questa sezione viene scritto un metodo Initialize per popolare il database con i dati di test.In this section, an Initialize method is written to populate it with test data.

Nella cartella Data (Dati) creare un nuovo file di classe denominato DbInitializer.cs e aggiungere il codice seguente:In the Data folder, create a new class file named DbInitializer.cs and add the following code:

using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Models
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            context.Database.EnsureCreated();

            // Look for any students.
            if (context.Student.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Student.Add(s);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Course.Add(c);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollment.Add(e);
            }
            context.SaveChanges();
        }
    }
}

Nota: Il codice precedente usa Models per lo spazio dei nomi (namespace ContosoUniversity.Models) invece di Data.Note: The preceding code uses Models for the namespace (namespace ContosoUniversity.Models) rather than Data. Models è coerente con il codice generato dallo scaffolder.Models is consistent with the scaffolder-generated code. Per altre informazioni, vedere questo problema relativo allo scaffolding in GitHub.For more information, see this GitHub scaffolding issue.

Il codice controlla se esistono studenti nel database.The code checks if there are any students in the DB. Se il database non contiene studenti, il database viene inizializzato con i dati di test.If there are no students in the DB, the DB is initialized with test data. I dati di test vengono caricati in matrici anziché in raccolte List<T> per ottimizzare le prestazioni.It loads test data into arrays rather than List<T> collections to optimize performance.

Il metodo EnsureCreated crea automaticamente il database per il contesto di database.The EnsureCreated method automatically creates the DB for the DB context. Se il database esiste, EnsureCreated restituisce senza modificare il database.If the DB exists, EnsureCreated returns without modifying the DB.

In Program.cs modificare il metodo Main per chiamare Initialize:In Program.cs, modify the Main method to call Initialize:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;

            try
            {
                var context = services.GetRequiredService<SchoolContext>();
                // using ContosoUniversity.Data; 
                DbInitializer.Initialize(context);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred creating the DB.");
            }
        }

        host.Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Arrestare l'app se è in esecuzione ed eseguire il comando seguente nella console di Gestione pacchetti:Stop the app if it's running, and run the following command in the Package Manager Console (PMC):

Drop-Database

Visualizzare il databaseView the DB

Il nome del database viene generato dal nome del contesto specificato in precedenza con l'aggiunta di un trattino e un GUID.The database name is generated from the context name you provided earlier plus a dash and a GUID. Di conseguenza, il nome del database sarà "SchoolContext-{GUID}".Thus, the database name will be "SchoolContext-{GUID}". Il GUID sarà diverso per ogni utente.The GUID will be different for each user. Aprire Esplora oggetti di SQL Server dal menu Visualizza in Visual Studio.Open SQL Server Object Explorer (SSOX) from the View menu in Visual Studio. In Esplora oggetti di SQL Server fare clic su (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID} .In SSOX, click (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}.

Espandere il nodo Tabelle.Expand the Tables node.

Fare clic con il pulsante destro del mouse sulla tabella Student (Studente) e fare clic su Visualizza dati per visualizzare le colonne create e le righe inserite nella tabella.Right-click the Student table and click View Data to see the columns created and the rows inserted into the table.

Codice asincronoAsynchronous code

La programmazione asincrona è la modalità predefinita per ASP.NET Core ed Entity Framework Core.Asynchronous programming is the default mode for ASP.NET Core and EF Core.

Per un server Web è disponibile un numero limitato di thread e in situazioni di carico elevato tutti i thread disponibili potrebbero essere in uso.A web server has a limited number of threads available, and in high load situations all of the available threads might be in use. In queste circostanze il server non può elaborare nuove richieste finché i thread non saranno liberi.When that happens, the server can't process new requests until the threads are freed up. Con il codice sincrono, può succedere che molti thread siano vincolati nonostante in quel momento non stiano eseguendo alcuna operazione. Rimangono tuttavia in attesa che l'operazione I/O sia completata.With synchronous code, many threads may be tied up while they aren't actually doing any work because they're waiting for I/O to complete. Con il codice asincrono, se un processo è in attesa del completamento dell'operazione I/O, il thread viene liberato e il server lo può usare per l'elaborazione di altre richieste.With asynchronous code, when a process is waiting for I/O to complete, its thread is freed up for the server to use for processing other requests. Di conseguenza, il codice asincrono consente un uso più efficiente delle risorse e il server è abilitato per gestire una maggiore quantità di traffico senza ritardi.As a result, asynchronous code enables server resources to be used more efficiently, and the server is enabled to handle more traffic without delays.

Il codice asincrono comporta un minimo sovraccarico in fase di esecuzione.Asynchronous code does introduce a small amount of overhead at run time. In caso di traffico ridotto, il calo delle prestazioni è irrilevante, mentre nelle situazioni di traffico elevato, è essenziale ottimizzare le prestazioni potenziali.For low traffic situations, the performance hit is negligible, while for high traffic situations, the potential performance improvement is substantial.

Nel codice seguente la parola chiave async, il valore restituito Task<T>, la parola chiave await e il metodo ToListAsync consentono di eseguire il codice in modo asincrono.In the following code, the async keyword, Task<T> return value, await keyword, and ToListAsync method make the code execute asynchronously.

public async Task OnGetAsync()
{
    Student = await _context.Student.ToListAsync();
}
  • La parola chiave async indica al compilatore di eseguire le operazioni seguenti:The async keyword tells the compiler to:

    • Generare callback per parti del corpo del metodo.Generate callbacks for parts of the method body.
    • Creare automaticamente l' oggetto Task restituito.Automatically create the Task object that's returned. Per altre informazioni, vedere Tipo restituito Task.For more information, see Task Return Type.
  • Il tipo restituito implicito Task rappresenta il lavoro in corso.The implicit return type Task represents ongoing work.

  • La parola chiave await indica al compilatore di suddividere il metodo in due parti.The await keyword causes the compiler to split the method into two parts. La prima parte termina con l'operazione avviata in modo asincrono.The first part ends with the operation that's started asynchronously. La seconda parte viene inserita in un metodo di callback che viene chiamato al termine dell'operazione.The second part is put into a callback method that's called when the operation completes.

  • ToListAsync è la versione asincrona del metodo di estensione ToList.ToListAsync is the asynchronous version of the ToList extension method.

Alcuni aspetti da considerare quando si scrive codice asincrono usato da Entity Framework Core:Some things to be aware of when writing asynchronous code that uses EF Core:

  • Solo le istruzioni che generano query o comandi da inviare al database vengono eseguite in modo asincrono.Only statements that cause queries or commands to be sent to the DB are executed asynchronously. Sono incluse ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync e SaveChangesAsync.That includes, ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, and SaveChangesAsync. Non sono incluse le istruzioni che modificano solo un oggetto IQueryable, ad esempio var students = context.Students.Where(s => s.LastName == "Davolio").It doesn't include statements that just change an IQueryable, such as var students = context.Students.Where(s => s.LastName == "Davolio").
  • Un contesto di Entity Framework Core non è thread-safe. Non tentare di eseguire più operazioni parallelamente.An EF Core context isn't thread safe: don't try to do multiple operations in parallel.
  • Per sfruttare i vantaggi del codice asincrono in termini di prestazioni, verificare che i pacchetti della libreria impiegati, ad esempio per il paging, usino la modalità asincrona per chiamare i metodi di Entity Framework Core che generano query da inviare al database.To take advantage of the performance benefits of async code, verify that library packages (such as for paging) use async if they call EF Core methods that send queries to the DB.

Per altre informazioni sulla programmazione asincrona in .NET, vedere Panoramica della programmazione asincrona e Programmazione asincrona con async e await.For more information about asynchronous programming in .NET, see Async Overview and Asynchronous programming with async and await.

Nella prossima esercitazione, vengono esaminate le operazioni CRUD per creare, leggere, aggiornare, eliminare ed elencare.In the next tutorial, basic CRUD (create, read, update, delete) operations are examined.

Risorse aggiuntiveAdditional resources