Parte 4, aggiungere un modello a un'app MVC core ASP.NET

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Di Rick Anderson e Jon P Smith.

In questa esercitazione vengono aggiunte classi per la gestione dei film in un database. Queste classi sono la parte "Model" dell'app MVC.

Queste classi di modello vengono usate con Entity Framework Core (EF Core) per lavorare con un database. EF Core è un framework ORM (Object-Relational Mapping) che semplifica il codice di accesso ai dati da scrivere.

Le classi di modello create sono note come classi POCO, da Plain Old CLR Objects. Le classi POCO non hanno alcuna dipendenza da EF Core. Definiscono solo le proprietà dei dati da archiviare nel database.

In questa esercitazione vengono create prima le classi di modelli e EF Core viene creato il database.

Aggiungere una classe del modello di dati

Fare clic con il pulsante destro del mouse sulla cartella >Modelli Aggiungi>classe. Denominare il file Movie.cs.

Aggiornare il Models/Movie.cs file con il codice seguente:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

La classe Movie contiene un campo Id, richiesto dal database per la chiave primaria.

L'attributo DataType su ReleaseDate specifica il tipo di dati (Date). Con questo attributo:

  • L'utente non deve immettere le informazioni sull'ora nel campo data.
  • Viene visualizzata solo la data, non le informazioni temporali.

L'attributo DataAnnotations viene analizzato in un'esercitazione successiva.

Il punto interrogativo dopo string indica che la proprietà è nullable. Per altre informazioni, vedere Tipi di riferimento Nullable.

Aggiungere i pacchetti NuGet di

Visual Studio installa automaticamente i pacchetti necessari.

Compilare il progetto per controllare se sono presenti errori del compilatore.

Eseguire lo scaffolding delle pagine Movie

Usare lo strumento di scaffolding per produrre Createpagine , Read, Updatee Delete (CRUD) per il modello di film.

In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Controllers e scegliere Aggiungi > nuovo elemento con scaffolding.

vista del passaggio precedente

Nella finestra di dialogo Aggiungi nuovo elemento con scaffolding:

  • Nel riquadro sinistro selezionare Installato>MVC comune.>
  • Selezionare Controller MVC con visualizzazioni usando Entity Framework.
  • Selezionare Aggiungi.

Finestra di dialogo Aggiungi scaffolding

Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :

  • Nell'elenco a discesa Classe modello selezionare Movie (MvcMovie.Models).
  • Nella riga Classe contesto di dati selezionare il segno più +.
    • Nella finestra di dialogo Aggiungi contesto dati viene generato il nome della classe MvcMovie.Data.MvcMovieContext.
    • Selezionare Aggiungi.
  • Nell'elenco a discesa Provider di database selezionare SQL Server.
  • Visualizzazioni e nome controller: mantenere l'impostazione predefinita.
  • Selezionare Aggiungi.

Aggiungi contesto dati mantiene le impostazioni predefinite

Se viene visualizzato un messaggio di errore, selezionare Aggiungi una seconda volta per riprovare.

Lo scaffolding aggiunge i pacchetti seguenti:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Lo scaffolding crea quanto segue:

  • Un controller di film: Controllers/MoviesController.cs
  • Razor visualizzare i file per le pagine Create, Delete, Details, Edit e Index : Views/Movies/*.cshtml
  • Classe di contesto del database: Data/MvcMovieContext.cs

Lo scaffolding aggiorna quanto segue:

  • Inserisce i riferimenti necessari al pacchetto nel file di MvcMovie.csproj progetto.
  • Registra il contesto del database nel Program.cs file.
  • Aggiunge un stringa di connessione di database al appsettings.json file.

La creazione automatica di questi file e aggiornamenti dei file è nota come scaffolding.

Le pagine con scaffolding non possono essere ancora usate perché il database non esiste. L'esecuzione dell'app e la selezione del collegamento Movie App comporta l'impossibilità di aprire un database o nessuna di queste tabelle: messaggio di errore movie.

Compilare l'app per verificare che non siano presenti errori.

Migrazione iniziale

Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.

Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.

Nella console Gestione pacchetti immettere il comando seguente:

Add-Migration InitialCreate

  • Add-Migration InitialCreate: genera un Migrations/{timestamp}_InitialCreate.cs file di migrazione. L'argomento InitialCreate è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext.

Viene visualizzato l'avviso seguente, risolto in un passaggio successivo:

Non è stato specificato alcun tipo di archivio per la proprietà decimale 'Price' nel tipo di entità 'Movie'. This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Specificare in modo esplicito il tipo di colonna di SQL Server in grado di contenere tutti i valori in 'OnModelCreating' usando 'HasColumnType', specificare precisione e scala usando 'HasPrecision' o configurare un convertitore di valori con 'HasConversion'.

In PMC immettere il comando seguente:

Update-Database

  • Update-Database: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up metodo nel Migrations/{time-stamp}_InitialCreate.cs file , che crea il database.

Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.

Testare l'app

Eseguire l'app e selezionare il collegamento App film.

Se si ottiene un'eccezione simile alla seguente, è possibile che il Update-Database comando non sia stato eseguito nel passaggio delle migrazioni:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese (Stati Uniti), è necessario localizzare l'app. Per istruzioni sulla localizzazione, vedere questo problema su GitHub.

Esaminare la classe di contesto del database generata e la registrazione

Con EF Core, l'accesso ai dati viene eseguito usando un modello. Un modello è costituito da classi di entità e da un contesto dell'oggetto che rappresenta una sessione con il database che consente di eseguire query e salvare i dati. Il contesto di database viene derivato da Microsoft.EntityFrameworkCore.DbContext e specifica le entità da includere nel modello di dati.

Lo scaffolding crea la classe di contesto del Data/MvcMovieContext.cs database:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; } = default!;
    }
}

Il codice precedente crea una proprietà DbSet<Movie> che rappresenta i film nel database.

Inserimento delle dipendenze

ASP.NET Core viene compilato con l'inserimento di dipendenze. I servizi, ad esempio il contesto del database, vengono registrati con l'inserimento delle dipendenze in Program.cs. Questi servizi vengono forniti ai componenti che li richiedono tramite parametri del costruttore.

Controllers/MoviesController.cs Nel file il costruttore usa l'inserimento delle dipendenze per inserire il contesto del MvcMovieContext database nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Lo scaffolding ha generato il codice evidenziato seguente in Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));

Il sistema di configurazione ASP.NET Core legge il database "MvcMovieContext" stringa di connessione.

Esaminare il database generato stringa di connessione

Lo scaffolding ha aggiunto un stringa di connessione al appsettings.json file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-4ebefa10-de29-4dea-b2ad-8a8dc6bcf374;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

Per lo sviluppo locale, il sistema di configurazione ASP.NET Core legge la ConnectionString chiave dal appsettings.json file.

Classe InitialCreate

Esaminare il file di Migrations/{timestamp}_InitialCreate.cs migrazione:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    /// <inheritdoc />
    public partial class InitialCreate : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

Nel codice precedente:

  • InitialCreate.Up crea la tabella Movie e configura Id come chiave primaria.
  • InitialCreate.Down ripristina le modifiche dello schema apportate dalla Up migrazione.

Inserimento delle dipendenze nel controller

Aprire il Controllers/MoviesController.cs file ed esaminare il costruttore:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Il costruttore usa l'inserimento dipendenze per inserire il contesto del database (MvcMovieContext) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Testare la pagina Create. Immettere e inviare i dati.

Testare le pagine Edit, Details e Delete.

Modelli fortemente tipizzati e direttiva @model

In un passaggio precedente di questa esercitazione è stato esaminato come un controller può passare oggetti o dati a una vista usando il dizionario ViewData. Il dizionario ViewData è un oggetto dinamico che fornisce un modo pratico ad associazione tardiva per passare informazioni a una vista.

MVC consente di passare oggetti modello fortemente tipizzati a una visualizzazione. Questo approccio fortemente tipizzato consente il controllo del codice in fase di compilazione. Il meccanismo di scaffolding ha passato un modello fortemente tipizzato nella classe e nelle MoviesController viste.

Esaminare il metodo generato Details nel Controllers/MoviesController.cs file:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

In genere il parametro id viene passato come dati di route. Ad esempio, https://localhost:5001/movies/details/1 imposta:

  • Il controller al movies controller, il primo segmento di URL.
  • Azione su details, il secondo segmento di URL.
  • Da id a 1, ultimo segmento di URL.

L'oggetto id può essere passato con una stringa di query, come nell'esempio seguente:

https://localhost:5001/movies/details?id=1

Il id parametro è definito come un tipo nullable (int?) nei casi in cui il id valore non viene specificato.

Un'espressione lambda viene passata al FirstOrDefaultAsync metodo per selezionare le entità film che corrispondono ai dati di route o al valore della stringa di query.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Se viene trovato un film, viene passata un'istanza del modello Movie alla vista Details:

return View(movie);

Esaminare il contenuto del Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

L'istruzione @model all'inizio del file di vista specifica il tipo di oggetto previsto dalla vista. Quando è stato creato il controller dei film, è stata inclusa l'istruzione @model seguente:

@model MvcMovie.Models.Movie

Questa direttiva @model consente di accedere al film che il controller ha passato alla vista. L'oggetto Model è fortemente tipizzato. Nella visualizzazione, ad esempio, Details.cshtml il codice passa ogni campo filmato agli DisplayNameFor helper HTML e DisplayFor con l'oggetto fortemente tipizzato Model . Le viste e i metodi Create e Edit passano anche un oggetto modello Movie.

Esaminare la Index.cshtml visualizzazione e il Index metodo nel controller Movies. Si noti che il codice crea un oggetto List quando chiama il metodo View. Il codice passa questo elenco Movies dal metodo di azione Index alla vista:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Il codice restituisce i dettagli del problema se la Movie proprietà del contesto di dati è Null.

Quando è stato creato il controller movies, lo scaffolding includeva l'istruzione seguente @model all'inizio del Index.cshtml file:

@model IEnumerable<MvcMovie.Models.Movie>

La @model direttiva consente l'accesso all'elenco di film passati dal controller alla visualizzazione usando un Model oggetto fortemente tipizzato. Ad esempio, nella Index.cshtml visualizzazione il codice scorre i filmati con un'istruzione foreach sull'oggetto fortemente tipizzato Model :

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Poiché l'oggetto Model è fortemente tipizzato come IEnumerable<Movie> oggetto , ogni elemento del ciclo viene tipizzato come Movie. Tra gli altri vantaggi, il compilatore convalida i tipi usati nel codice.

Risorse aggiuntive

In questa esercitazione vengono aggiunte classi per la gestione dei film in un database. Queste classi sono la parte "Model" dell'app MVC.

Queste classi di modello vengono usate con Entity Framework Core (EF Core) per lavorare con un database. EF Core è un framework ORM (Object-Relational Mapping) che semplifica il codice di accesso ai dati da scrivere.

Le classi di modello create sono note come classi POCO, da Plain Old CLR Objects. Le classi POCO non hanno alcuna dipendenza da EF Core. Definiscono solo le proprietà dei dati da archiviare nel database.

In questa esercitazione vengono create prima le classi di modelli e EF Core viene creato il database.

Aggiungere una classe del modello di dati

Fare clic con il pulsante destro del mouse sulla cartella >Modelli Aggiungi>classe. Denominare il file Movie.cs.

Aggiornare il Models/Movie.cs file con il codice seguente:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

La classe Movie contiene un campo Id, richiesto dal database per la chiave primaria.

L'attributo DataType su ReleaseDate specifica il tipo di dati (Date). Con questo attributo:

  • L'utente non deve immettere le informazioni sull'ora nel campo data.
  • Viene visualizzata solo la data, non le informazioni temporali.

L'attributo DataAnnotations viene analizzato in un'esercitazione successiva.

Il punto interrogativo dopo string indica che la proprietà è nullable. Per altre informazioni, vedere Tipi di riferimento Nullable.

Aggiungere i pacchetti NuGet di

Visual Studio installa automaticamente i pacchetti necessari.

Compilare il progetto per controllare se sono presenti errori del compilatore.

Eseguire lo scaffolding delle pagine Movie

Usare lo strumento di scaffolding per produrre Createpagine , Read, Updatee Delete (CRUD) per il modello di film.

In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Controllers e scegliere Aggiungi > nuovo elemento con scaffolding.

vista del passaggio precedente

Nella finestra di dialogo Aggiungi nuovo elemento con scaffolding:

  • Nel riquadro sinistro selezionare Installato>MVC comune.>
  • Selezionare Controller MVC con visualizzazioni usando Entity Framework.
  • Selezionare Aggiungi.

Finestra di dialogo Aggiungi scaffolding

Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :

  • Nell'elenco a discesa Classe modello selezionare Movie (MvcMovie.Models).
  • Nella riga Classe contesto di dati selezionare il segno più +.
    • Nella finestra di dialogo Aggiungi contesto dati viene generato il nome della classe MvcMovie.Data.MvcMovieContext.
    • Selezionare Aggiungi.
  • Nell'elenco a discesa Provider di database selezionare SQL Server.
  • Visualizzazioni e nome controller: mantenere l'impostazione predefinita.
  • Selezionare Aggiungi.

Aggiungi contesto dati mantiene le impostazioni predefinite

Se viene visualizzato un messaggio di errore, selezionare Aggiungi una seconda volta per riprovare.

Lo scaffolding aggiunge i pacchetti seguenti:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Lo scaffolding crea quanto segue:

  • Un controller di film: Controllers/MoviesController.cs
  • Razor visualizzare i file per le pagine Create, Delete, Details, Edit e Index : Views/Movies/*.cshtml
  • Classe di contesto del database: Data/MvcMovieContext.cs

Lo scaffolding aggiorna quanto segue:

  • Inserisce i riferimenti necessari al pacchetto nel file di MvcMovie.csproj progetto.
  • Registra il contesto del database nel Program.cs file.
  • Aggiunge un stringa di connessione di database al appsettings.json file.

La creazione automatica di questi file e aggiornamenti dei file è nota come scaffolding.

Le pagine con scaffolding non possono essere ancora usate perché il database non esiste. L'esecuzione dell'app e la selezione del collegamento Movie App comporta l'impossibilità di aprire un database o nessuna di queste tabelle: messaggio di errore movie.

Compilare l'app per verificare che non siano presenti errori.

Migrazione iniziale

Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.

Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.

Nella console di Gestione pacchetti immettere i comandi seguenti:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: genera un Migrations/{timestamp}_InitialCreate.cs file di migrazione. L'argomento InitialCreate è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext.

  • Update-Database: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up metodo nel Migrations/{time-stamp}_InitialCreate.cs file , che crea il database.

Il Update-Database comando genera l'avviso seguente:

Non è stato specificato alcun tipo di archivio per la proprietà decimale 'Price' nel tipo di entità 'Movie'. This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Specificare in modo esplicito il tipo di colonna di SQL Server in grado di contenere tutti i valori in 'OnModelCreating' usando 'HasColumnType', specificare precisione e scala usando 'HasPrecision' o configurare un convertitore di valori con 'HasConversion'.

Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.

Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.

Testare l'app

Eseguire l'app e selezionare il collegamento App film.

Se si ottiene un'eccezione simile alla seguente, è possibile che il Update-Database comando non sia stato eseguito nel passaggio delle migrazioni:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese (Stati Uniti), è necessario localizzare l'app. Per istruzioni sulla localizzazione, vedere questo problema su GitHub.

Esaminare la classe di contesto del database generata e la registrazione

Con EF Core, l'accesso ai dati viene eseguito usando un modello. Un modello è costituito da classi di entità e da un contesto dell'oggetto che rappresenta una sessione con il database che consente di eseguire query e salvare i dati. Il contesto di database viene derivato da Microsoft.EntityFrameworkCore.DbContext e specifica le entità da includere nel modello di dati.

Lo scaffolding crea la classe di contesto del Data/MvcMovieContext.cs database:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Il codice precedente crea una proprietà DbSet<Movie> che rappresenta i film nel database.

Inserimento delle dipendenze

ASP.NET Core viene compilato con l'inserimento di dipendenze. I servizi, ad esempio il contesto del database, vengono registrati con l'inserimento delle dipendenze in Program.cs. Questi servizi vengono forniti ai componenti che li richiedono tramite parametri del costruttore.

Controllers/MoviesController.cs Nel file il costruttore usa l'inserimento delle dipendenze per inserire il contesto del MvcMovieContext database nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Lo scaffolding ha generato il codice evidenziato seguente in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

Il sistema di configurazione ASP.NET Core legge il database "MvcMovieContext" stringa di connessione.

Esaminare il database generato stringa di connessione

Lo scaffolding ha aggiunto un stringa di connessione al appsettings.json file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Data Source=MvcMovieContext-ea7a4069-f366-4742-bd1c-3f753a804ce1.db"
  }
}

Per lo sviluppo locale, il sistema di configurazione ASP.NET Core legge la ConnectionString chiave dal appsettings.json file.

Classe InitialCreate

Esaminare il file di Migrations/{timestamp}_InitialCreate.cs migrazione:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

Nel codice precedente:

  • InitialCreate.Up crea la tabella Movie e configura Id come chiave primaria.
  • InitialCreate.Down ripristina le modifiche dello schema apportate dalla Up migrazione.

Inserimento delle dipendenze nel controller

Aprire il Controllers/MoviesController.cs file ed esaminare il costruttore:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Il costruttore usa l'inserimento dipendenze per inserire il contesto del database (MvcMovieContext) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Testare la pagina Create. Immettere e inviare i dati.

Testare le pagine Edit, Details e Delete.

Modelli fortemente tipizzati e direttiva @model

In un passaggio precedente di questa esercitazione è stato esaminato come un controller può passare oggetti o dati a una vista usando il dizionario ViewData. Il dizionario ViewData è un oggetto dinamico che fornisce un modo pratico ad associazione tardiva per passare informazioni a una vista.

MVC consente di passare oggetti modello fortemente tipizzati a una visualizzazione. Questo approccio fortemente tipizzato consente il controllo del codice in fase di compilazione. Il meccanismo di scaffolding ha passato un modello fortemente tipizzato nella classe e nelle MoviesController viste.

Esaminare il metodo generato Details nel Controllers/MoviesController.cs file:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

In genere il parametro id viene passato come dati di route. Ad esempio, https://localhost:5001/movies/details/1 imposta:

  • Il controller al movies controller, il primo segmento di URL.
  • Azione su details, il secondo segmento di URL.
  • Da id a 1, ultimo segmento di URL.

L'oggetto id può essere passato con una stringa di query, come nell'esempio seguente:

https://localhost:5001/movies/details?id=1

Il id parametro è definito come un tipo nullable (int?) nei casi in cui il id valore non viene specificato.

Un'espressione lambda viene passata al FirstOrDefaultAsync metodo per selezionare le entità film che corrispondono ai dati di route o al valore della stringa di query.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Se viene trovato un film, viene passata un'istanza del modello Movie alla vista Details:

return View(movie);

Esaminare il contenuto del Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

L'istruzione @model all'inizio del file di vista specifica il tipo di oggetto previsto dalla vista. Quando è stato creato il controller dei film, è stata inclusa l'istruzione @model seguente:

@model MvcMovie.Models.Movie

Questa direttiva @model consente di accedere al film che il controller ha passato alla vista. L'oggetto Model è fortemente tipizzato. Nella visualizzazione, ad esempio, Details.cshtml il codice passa ogni campo filmato agli DisplayNameFor helper HTML e DisplayFor con l'oggetto fortemente tipizzato Model . Le viste e i metodi Create e Edit passano anche un oggetto modello Movie.

Esaminare la Index.cshtml visualizzazione e il Index metodo nel controller Movies. Si noti che il codice crea un oggetto List quando chiama il metodo View. Il codice passa questo elenco Movies dal metodo di azione Index alla vista:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Il codice restituisce i dettagli del problema se la Movie proprietà del contesto di dati è Null.

Quando è stato creato il controller movies, lo scaffolding includeva l'istruzione seguente @model all'inizio del Index.cshtml file:

@model IEnumerable<MvcMovie.Models.Movie>

La @model direttiva consente l'accesso all'elenco di film passati dal controller alla visualizzazione usando un Model oggetto fortemente tipizzato. Ad esempio, nella Index.cshtml visualizzazione il codice scorre i filmati con un'istruzione foreach sull'oggetto fortemente tipizzato Model :

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Poiché l'oggetto Model è fortemente tipizzato come IEnumerable<Movie> oggetto , ogni elemento del ciclo viene tipizzato come Movie. Tra gli altri vantaggi, il compilatore convalida i tipi usati nel codice.

Risorse aggiuntive

In questa esercitazione vengono aggiunte classi per la gestione dei film in un database. Queste classi sono la parte "Model" dell'app MVC.

Queste classi di modello vengono usate con Entity Framework Core (EF Core) per lavorare con un database. EF Core è un framework ORM (Object-Relational Mapping) che semplifica il codice di accesso ai dati da scrivere.

Le classi di modello create sono note come classi POCO, da Plain Old CLR Objects. Le classi POCO non hanno alcuna dipendenza da EF Core. Definiscono solo le proprietà dei dati da archiviare nel database.

In questa esercitazione vengono create prima le classi di modelli e EF Core viene creato il database.

Aggiungere una classe del modello di dati

Fare clic con il pulsante destro del mouse sulla cartella >Modelli Aggiungi>classe. Denominare il file Movie.cs.

Aggiornare il Models/Movie.cs file con il codice seguente:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

La classe Movie contiene un campo Id, richiesto dal database per la chiave primaria.

L'attributo DataType su ReleaseDate specifica il tipo di dati (Date). Con questo attributo:

  • L'utente non deve immettere le informazioni sull'ora nel campo data.
  • Viene visualizzata solo la data, non le informazioni temporali.

L'attributo DataAnnotations viene analizzato in un'esercitazione successiva.

Il punto interrogativo dopo string indica che la proprietà è nullable. Per altre informazioni, vedere Tipi di riferimento Nullable.

Aggiungere i pacchetti NuGet di

Visual Studio installa automaticamente i pacchetti necessari.

Compilare il progetto per controllare se sono presenti errori del compilatore.

Eseguire lo scaffolding delle pagine Movie

Usare lo strumento di scaffolding per produrre Createpagine , Read, Updatee Delete (CRUD) per il modello di film.

In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Controllers e scegliere Aggiungi > nuovo elemento con scaffolding.

vista del passaggio precedente

Nella finestra di dialogo Aggiungi nuovo elemento con scaffolding:

  • Nel riquadro sinistro selezionare Installato>MVC comune.>
  • Selezionare Controller MVC con visualizzazioni usando Entity Framework.
  • Selezionare Aggiungi.

Finestra di dialogo Aggiungi scaffolding

Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :

  • Nell'elenco a discesa Classe modello selezionare Movie (MvcMovie.Models).
  • Nella riga Classe contesto di dati selezionare il segno più +.
    • Nella finestra di dialogo Aggiungi contesto dati viene generato il nome della classe MvcMovie.Data.MvcMovieContext.
    • Selezionare Aggiungi.
  • Nell'elenco a discesa Provider di database selezionare SQL Server.
  • Visualizzazioni e nome controller: mantenere l'impostazione predefinita.
  • Selezionare Aggiungi.

Aggiungi contesto dati mantiene le impostazioni predefinite Se viene visualizzato un messaggio di errore, selezionare Aggiungi una seconda volta per riprovare.

Lo scaffolding aggiunge i pacchetti seguenti:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Lo scaffolding crea quanto segue:

  • Un controller di film: Controllers/MoviesController.cs
  • Razor visualizzare i file per le pagine Create, Delete, Details, Edit e Index : Views/Movies/*.cshtml
  • Classe di contesto del database: Data/MvcMovieContext.cs

Lo scaffolding aggiorna quanto segue:

  • Inserisce i riferimenti necessari al pacchetto nel file di MvcMovie.csproj progetto.
  • Registra il contesto del database nel Program.cs file.
  • Aggiunge un stringa di connessione di database al appsettings.json file.

La creazione automatica di questi file e aggiornamenti dei file è nota come scaffolding.

Le pagine con scaffolding non possono essere ancora usate perché il database non esiste. L'esecuzione dell'app e la selezione del collegamento Movie App comporta l'impossibilità di aprire un database o nessuna di queste tabelle: messaggio di errore movie.

Compilare l'app per verificare che non siano presenti errori.

Migrazione iniziale

Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.

Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.

Nella console di Gestione pacchetti immettere i comandi seguenti:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: genera un Migrations/{timestamp}_InitialCreate.cs file di migrazione. L'argomento InitialCreate è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext.

  • Update-Database: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up metodo nel Migrations/{time-stamp}_InitialCreate.cs file , che crea il database.

Il Update-Database comando genera l'avviso seguente:

No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').

Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.

Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.

Testare l'app

Eseguire l'app e selezionare il collegamento App film.

Se si ottiene un'eccezione simile alla seguente, è possibile che il Update-Database comando non sia stato eseguito nel passaggio delle migrazioni:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese (Stati Uniti), è necessario localizzare l'app. Per istruzioni sulla localizzazione, vedere questo problema su GitHub.

Esaminare la classe di contesto del database generata e la registrazione

Con EF Core, l'accesso ai dati viene eseguito usando un modello. Un modello è costituito da classi di entità e da un contesto dell'oggetto che rappresenta una sessione con il database che consente di eseguire query e salvare i dati. Il contesto di database viene derivato da Microsoft.EntityFrameworkCore.DbContext e specifica le entità da includere nel modello di dati.

Lo scaffolding crea la classe di contesto del Data/MvcMovieContext.cs database:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Il codice precedente crea una proprietà DbSet<Movie> che rappresenta i film nel database.

Inserimento delle dipendenze

ASP.NET Core viene compilato con l'inserimento di dipendenze. I servizi, ad esempio il contesto del database, vengono registrati con l'inserimento delle dipendenze in Program.cs. Questi servizi vengono forniti ai componenti che li richiedono tramite parametri del costruttore.

Controllers/MoviesController.cs Nel file il costruttore usa l'inserimento delle dipendenze per inserire il contesto del MvcMovieContext database nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Lo scaffolding ha generato il codice evidenziato seguente in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

Il sistema di configurazione ASP.NET Core legge il database "MvcMovieContext" stringa di connessione.

Esaminare il database generato stringa di connessione

Lo scaffolding ha aggiunto un stringa di connessione al appsettings.json file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Data Source=MvcMovieContext-ea7a4069-f366-4742-bd1c-3f753a804ce1.db"
  }
}

Per lo sviluppo locale, il sistema di configurazione ASP.NET Core legge la ConnectionString chiave dal appsettings.json file.

Classe InitialCreate

Esaminare il file di Migrations/{timestamp}_InitialCreate.cs migrazione:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

Nel codice precedente:

  • InitialCreate.Up crea la tabella Movie e configura Id come chiave primaria.
  • InitialCreate.Down ripristina le modifiche dello schema apportate dalla Up migrazione.

Inserimento delle dipendenze nel controller

Aprire il Controllers/MoviesController.cs file ed esaminare il costruttore:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Il costruttore usa l'inserimento dipendenze per inserire il contesto del database (MvcMovieContext) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Testare la pagina Create. Immettere e inviare i dati.

Testare le pagine Edit, Details e Delete.

Modelli fortemente tipizzati e direttiva @model

In un passaggio precedente di questa esercitazione è stato esaminato come un controller può passare oggetti o dati a una vista usando il dizionario ViewData. Il dizionario ViewData è un oggetto dinamico che fornisce un modo pratico ad associazione tardiva per passare informazioni a una vista.

MVC consente di passare oggetti modello fortemente tipizzati a una visualizzazione. Questo approccio fortemente tipizzato consente il controllo del codice in fase di compilazione. Il meccanismo di scaffolding ha passato un modello fortemente tipizzato nella classe e nelle MoviesController viste.

Esaminare il metodo generato Details nel Controllers/MoviesController.cs file:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

In genere il parametro id viene passato come dati di route. Ad esempio, https://localhost:5001/movies/details/1 imposta:

  • Il controller al movies controller, il primo segmento di URL.
  • Azione su details, il secondo segmento di URL.
  • Da id a 1, ultimo segmento di URL.

L'oggetto id può essere passato con una stringa di query, come nell'esempio seguente:

https://localhost:5001/movies/details?id=1

Il id parametro è definito come un tipo nullable (int?) nei casi in cui il id valore non viene specificato.

Un'espressione lambda viene passata al FirstOrDefaultAsync metodo per selezionare le entità film che corrispondono ai dati di route o al valore della stringa di query.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Se viene trovato un film, viene passata un'istanza del modello Movie alla vista Details:

return View(movie);

Esaminare il contenuto del Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

L'istruzione @model all'inizio del file di vista specifica il tipo di oggetto previsto dalla vista. Quando è stato creato il controller dei film, è stata inclusa l'istruzione @model seguente:

@model MvcMovie.Models.Movie

Questa direttiva @model consente di accedere al film che il controller ha passato alla vista. L'oggetto Model è fortemente tipizzato. Nella visualizzazione, ad esempio, Details.cshtml il codice passa ogni campo filmato agli DisplayNameFor helper HTML e DisplayFor con l'oggetto fortemente tipizzato Model . Le viste e i metodi Create e Edit passano anche un oggetto modello Movie.

Esaminare la Index.cshtml visualizzazione e il Index metodo nel controller Movies. Si noti che il codice crea un oggetto List quando chiama il metodo View. Il codice passa questo elenco Movies dal metodo di azione Index alla vista:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Il codice restituisce i dettagli del problema se la Movie proprietà del contesto di dati è Null.

Quando è stato creato il controller movies, lo scaffolding includeva l'istruzione seguente @model all'inizio del Index.cshtml file:

@model IEnumerable<MvcMovie.Models.Movie>

La @model direttiva consente l'accesso all'elenco di film passati dal controller alla visualizzazione usando un Model oggetto fortemente tipizzato. Ad esempio, nella Index.cshtml visualizzazione il codice scorre i filmati con un'istruzione foreach sull'oggetto fortemente tipizzato Model :

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Poiché l'oggetto Model è fortemente tipizzato come IEnumerable<Movie> oggetto , ogni elemento del ciclo viene tipizzato come Movie. Tra gli altri vantaggi, il compilatore convalida i tipi usati nel codice.

Risorse aggiuntive

In questa esercitazione vengono aggiunte classi per la gestione dei film in un database. Queste classi sono la parte "Model" dell'app MVC.

Queste classi di modello vengono usate con Entity Framework Core (EF Core) per lavorare con un database. EF Core è un framework ORM (Object-Relational Mapping) che semplifica il codice di accesso ai dati da scrivere.

Le classi di modello create sono note come classi POCO, da Plain Old CLR Objects. Le classi POCO non hanno alcuna dipendenza da EF Core. Definiscono solo le proprietà dei dati da archiviare nel database.

In questa esercitazione vengono create prima le classi di modelli e EF Core viene creato il database.

Aggiungere una classe del modello di dati

Fare clic con il pulsante destro del mouse sulla cartella >Modelli Aggiungi>classe. Denominare il file Movie.cs.

Aggiornare il Models/Movie.cs file con il codice seguente:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string? Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string? Genre { get; set; }
        public decimal Price { get; set; }
    }
}

La classe Movie contiene un campo Id, richiesto dal database per la chiave primaria.

L'attributo DataType su ReleaseDate specifica il tipo di dati (Date). Con questo attributo:

  • L'utente non deve immettere le informazioni sull'ora nel campo data.
  • Viene visualizzata solo la data, non le informazioni temporali.

L'attributo DataAnnotations viene analizzato in un'esercitazione successiva.

Il punto interrogativo dopo string indica che la proprietà è nullable. Per altre informazioni, vedere Tipi di riferimento Nullable.

Aggiungere i pacchetti NuGet di

Dal menu Strumenti scegliere Gestione pacchetti NuGet>Console di Gestione pacchetti.

Menu della Console di Gestione pacchetti

Nella console di Gestione pacchetti eseguire il comando seguente:

Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.SqlServer

I comandi precedenti aggiungono:

  • Provider EF Core SQL Server. Il pacchetto del provider installa il EF Core pacchetto come dipendenza.
  • Le utilità usate dai pacchetti installati automaticamente nel passaggio di scaffolding, più avanti nell'esercitazione.

Compilare il progetto per controllare se sono presenti errori del compilatore.

Eseguire lo scaffolding delle pagine Movie

Usare lo strumento di scaffolding per produrre Createpagine , Read, Updatee Delete (CRUD) per il modello di film.

In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Controllers e scegliere Aggiungi > nuovo elemento con scaffolding.

vista del passaggio precedente

Nella finestra di dialogo Aggiungi scaffolding selezionare Controller MVC con visualizzazioni, usando Entity Framework > Aggiungi.

Finestra di dialogo Aggiungi scaffolding

Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :

  • Nell'elenco a discesa Classe modello selezionare Movie (MvcMovie.Models).
  • Nella riga Classe contesto di dati selezionare il segno più +.
    • Nella finestra di dialogo Aggiungi contesto dati viene generato il nome della classe MvcMovie.Data.MvcMovieContext.
    • Selezionare Aggiungi.
  • Visualizzazioni e nome controller: mantenere l'impostazione predefinita.
  • Selezionare Aggiungi.

Aggiungi contesto dati mantiene le impostazioni predefinite

Se viene visualizzato un messaggio di errore, selezionare Aggiungi una seconda volta per riprovare.

Lo scaffolding aggiorna quanto segue:

  • Inserisce i riferimenti necessari al pacchetto nel file di MvcMovie.csproj progetto.
  • Registra il contesto del database nel Program.cs file.
  • Aggiunge un stringa di connessione di database al appsettings.json file.

Lo scaffolding crea quanto segue:

  • Un controller di film: Controllers/MoviesController.cs
  • Razor visualizzare i file per le pagine Create, Delete, Details, Edit e Index : Views/Movies/*.cshtml
  • Classe di contesto del database: Data/MvcMovieContext.cs

La creazione automatica di questi file e aggiornamenti dei file è nota come scaffolding.

Le pagine con scaffolding non possono essere ancora usate perché il database non esiste. L'esecuzione dell'app e la selezione del collegamento Movie App comporta l'impossibilità di aprire un database o nessuna di queste tabelle: messaggio di errore movie.

Creare l'app

Compilazione dell'app. Il compilatore genera diversi avvisi sulla modalità null di gestione dei valori. Per altre informazioni, vedere questo problema di GitHub e i tipi di riferimento Nullable.

Per eliminare gli avvisi dai tipi riferimento nullable, rimuovere la riga seguente dal MvcMovie.csproj file:

<Nullable>enable</Nullable>

Ci auguriamo di risolvere questo problema nella versione successiva.

Migrazione iniziale

Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.

Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.

Nella console di Gestione pacchetti immettere i comandi seguenti:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: genera un Migrations/{timestamp}_InitialCreate.cs file di migrazione. L'argomento InitialCreate è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext.

  • Update-Database: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up metodo nel Migrations/{time-stamp}_InitialCreate.cs file , che crea il database.

Il Update-Database comando genera l'avviso seguente:

No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').

Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.

Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.

Testare l'app

Eseguire l'app e selezionare il collegamento App film.

Se si ottiene un'eccezione simile alla seguente, è possibile che il passaggio delle migrazioni non sia stato ottenuto:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese (Stati Uniti), è necessario localizzare l'app. Per istruzioni sulla localizzazione, vedere questo problema su GitHub.

Esaminare la classe di contesto del database generata e la registrazione

Con EF Core, l'accesso ai dati viene eseguito usando un modello. Un modello è costituito da classi di entità e da un contesto dell'oggetto che rappresenta una sessione con il database che consente di eseguire query e salvare i dati. Il contesto di database viene derivato da Microsoft.EntityFrameworkCore.DbContext e specifica le entità da includere nel modello di dati.

Lo scaffolding crea la classe di contesto del Data/MvcMovieContext.cs database:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Il codice precedente crea una proprietà DbSet<Movie> che rappresenta i film nel database.

Inserimento delle dipendenze

ASP.NET Core viene compilato con l'inserimento di dipendenze. I servizi, ad esempio il contesto del database, vengono registrati con l'inserimento delle dipendenze in Program.cs. Questi servizi vengono forniti ai componenti che li richiedono tramite parametri del costruttore.

Controllers/MoviesController.cs Nel file il costruttore usa l'inserimento delle dipendenze per inserire il contesto del MvcMovieContext database nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Lo scaffolding ha generato il codice evidenziato seguente in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

Il sistema di configurazione ASP.NET Core legge il database "MvcMovieContext" stringa di connessione.

Esaminare il database generato stringa di connessione

Lo scaffolding ha aggiunto un stringa di connessione al appsettings.json file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-7dc5;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

Per lo sviluppo locale, il sistema di configurazione ASP.NET Core legge la ConnectionString chiave dal appsettings.json file.

Classe InitialCreate

Esaminare il file di Migrations/{timestamp}_InitialCreate.cs migrazione:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

Nel codice precedente:

  • InitialCreate.Up crea la tabella Movie e configura Id come chiave primaria.
  • InitialCreate.Down ripristina le modifiche dello schema apportate dalla Up migrazione.

Inserimento delle dipendenze nel controller

Aprire il Controllers/MoviesController.cs file ed esaminare il costruttore:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Il costruttore usa l'inserimento dipendenze per inserire il contesto del database (MvcMovieContext) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Testare la pagina Create. Immettere e inviare i dati.

Testare le pagine Edit, Details e Delete.

Modelli fortemente tipizzati e direttiva @model

In un passaggio precedente di questa esercitazione è stato esaminato come un controller può passare oggetti o dati a una vista usando il dizionario ViewData. Il dizionario ViewData è un oggetto dinamico che fornisce un modo pratico ad associazione tardiva per passare informazioni a una vista.

MVC consente di passare oggetti modello fortemente tipizzati a una visualizzazione. Questo approccio fortemente tipizzato consente il controllo del codice in fase di compilazione. Il meccanismo di scaffolding ha passato un modello fortemente tipizzato nella classe e nelle MoviesController viste.

Esaminare il metodo generato Details nel Controllers/MoviesController.cs file:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

In genere il parametro id viene passato come dati di route. Ad esempio, https://localhost:5001/movies/details/1 imposta:

  • Il controller al movies controller, il primo segmento di URL.
  • Azione su details, il secondo segmento di URL.
  • Da id a 1, ultimo segmento di URL.

L'oggetto id può essere passato con una stringa di query, come nell'esempio seguente:

https://localhost:5001/movies/details?id=1

Il id parametro è definito come un tipo nullable (int?) nei casi in cui il id valore non viene specificato.

Un'espressione lambda viene passata al FirstOrDefaultAsync metodo per selezionare le entità film che corrispondono ai dati di route o al valore della stringa di query.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Se viene trovato un film, viene passata un'istanza del modello Movie alla vista Details:

return View(movie);

Esaminare il contenuto del Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

L'istruzione @model all'inizio del file di vista specifica il tipo di oggetto previsto dalla vista. Quando è stato creato il controller dei film, è stata inclusa l'istruzione @model seguente:

@model MvcMovie.Models.Movie

Questa direttiva @model consente di accedere al film che il controller ha passato alla vista. L'oggetto Model è fortemente tipizzato. Nella visualizzazione, ad esempio, Details.cshtml il codice passa ogni campo filmato agli DisplayNameFor helper HTML e DisplayFor con l'oggetto fortemente tipizzato Model . Le viste e i metodi Create e Edit passano anche un oggetto modello Movie.

Esaminare la Index.cshtml visualizzazione e il Index metodo nel controller Movies. Si noti che il codice crea un oggetto List quando chiama il metodo View. Il codice passa questo elenco Movies dal metodo di azione Index alla vista:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Quando è stato creato il controller movies, lo scaffolding includeva l'istruzione seguente @model all'inizio del Index.cshtml file:

@model IEnumerable<MvcMovie.Models.Movie>

La @model direttiva consente l'accesso all'elenco di film passati dal controller alla visualizzazione usando un Model oggetto fortemente tipizzato. Ad esempio, nella Index.cshtml visualizzazione il codice scorre i filmati con un'istruzione foreach sull'oggetto fortemente tipizzato Model :

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Poiché l'oggetto Model è fortemente tipizzato come IEnumerable<Movie> oggetto , ogni elemento del ciclo viene tipizzato come Movie. Tra gli altri vantaggi, il compilatore convalida i tipi usati nel codice.

Risorse aggiuntive

In questa esercitazione vengono aggiunte classi per la gestione dei film in un database. Queste classi sono la parte "Model" dell'app MVC.

Queste classi di modello vengono usate con Entity Framework Core (EF Core) per lavorare con un database. EF Core è un framework ORM (Object-Relational Mapping) che semplifica il codice di accesso ai dati da scrivere.

Le classi di modello create sono note come classi POCO, da Plain Old CLR Objects. Le classi POCO non hanno alcuna dipendenza da EF Core. Definiscono solo le proprietà dei dati da archiviare nel database.

In questa esercitazione vengono create prima le classi di modelli e EF Core viene creato il database.

Aggiungere una classe del modello di dati

Fare clic con il pulsante destro del mouse sulla cartella >Modelli Aggiungi>classe. Denominare il file Movie.cs.

Aggiornare il Models/Movie.cs file con il codice seguente:

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

La classe Movie contiene un campo Id, richiesto dal database per la chiave primaria.

L'attributo DataType su ReleaseDate specifica il tipo di dati (Date). Con questo attributo:

  • L'utente non deve immettere le informazioni sull'ora nel campo data.
  • Viene visualizzata solo la data, non le informazioni temporali.

L'attributo DataAnnotations viene analizzato in un'esercitazione successiva.

Aggiungere i pacchetti NuGet di

Dal menu Strumenti scegliere Gestione pacchetti NuGet>Console di Gestione pacchetti.

Menu della Console di Gestione pacchetti

Nella console di Gestione pacchetti eseguire il comando seguente:

Install-Package Microsoft.EntityFrameworkCore.Design

I comandi precedenti aggiungono:

  • Provider EF Core SQL Server. Il pacchetto del provider installa il EF Core pacchetto come dipendenza.
  • Le utilità usate dai pacchetti installati automaticamente nel passaggio di scaffolding, più avanti nell'esercitazione.

Compilare il progetto per controllare se sono presenti errori del compilatore.

Eseguire lo scaffolding delle pagine Movie

Usare lo strumento di scaffolding per produrre Createpagine , Read, Updatee Delete (CRUD) per il modello di film.

In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Controllers e scegliere Aggiungi > nuovo elemento con scaffolding.

vista del passaggio precedente

Nella finestra di dialogo Aggiungi scaffolding selezionare Controller MVC con visualizzazioni, usando Entity Framework > Aggiungi.

Finestra di dialogo Aggiungi scaffolding

Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :

  • Nell'elenco a discesa Classe modello selezionare Movie (MvcMovie.Models).
  • Nella riga Classe contesto di dati selezionare il segno più +.
    • Nella finestra di dialogo Aggiungi contesto dati viene generato il nome della classe MvcMovie.Data.MvcMovieContext.
    • Selezionare Aggiungi.
  • Visualizzazioni e nome controller: mantenere l'impostazione predefinita.
  • Selezionare Aggiungi.

Aggiungi contesto dati mantiene le impostazioni predefinite

Lo scaffolding aggiorna quanto segue:

  • Inserisce i riferimenti necessari al pacchetto nel file di MvcMovie.csproj progetto.
  • Registra il contesto del Startup.cs database nel Startup.ConfigureServices file.
  • Aggiunge un stringa di connessione di database al appsettings.json file.

Lo scaffolding crea quanto segue:

  • Un controller di film: Controllers/MoviesController.cs
  • Razor visualizzare i file per le pagine Create, Delete, Details, Edit e Index : Views/Movies/*.cshtml
  • Classe di contesto del database: Data/MvcMovieContext.cs

La creazione automatica di questi file e aggiornamenti dei file è nota come scaffolding.

Le pagine con scaffolding non possono essere ancora usate perché il database non esiste. L'esecuzione dell'app e la selezione del collegamento Movie App comporta l'impossibilità di aprire un database o nessuna di queste tabelle: messaggio di errore movie.

Migrazione iniziale

Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.

Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.

Nella console di Gestione pacchetti immettere i comandi seguenti:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: genera un Migrations/{timestamp}_InitialCreate.cs file di migrazione. L'argomento InitialCreate è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext.

  • Update-Database: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up metodo nel Migrations/{time-stamp}_InitialCreate.cs file , che crea il database.

Il Update-Database comando genera l'avviso seguente:

No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').

Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.

Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.

Testare l'app

Eseguire l'app e selezionare il collegamento App film.

Se si ottiene un'eccezione simile alla seguente, è possibile che il passaggio delle migrazioni non sia stato ottenuto:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Nota

Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese (Stati Uniti), è necessario localizzare l'app. Per istruzioni sulla localizzazione, vedere questo problema su GitHub.

Esaminare la classe di contesto del database generata e la registrazione

Con EF Core, l'accesso ai dati viene eseguito usando un modello. Un modello è costituito da classi di entità e da un contesto dell'oggetto che rappresenta una sessione con il database che consente di eseguire query e salvare i dati. Il contesto di database viene derivato da Microsoft.EntityFrameworkCore.DbContext e specifica le entità da includere nel modello di dati.

Lo scaffolding crea la classe di contesto del Data/MvcMovieContext.cs database:

using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<Movie> Movie { get; set; }
    }
}

Il codice precedente crea una proprietà DbSet<Movie> che rappresenta i film nel database.

ASP.NET Core viene compilato con l'inserimento di dipendenze. I servizi, ad esempio il contesto del database, devono essere registrati con l'inserimento delle dipendenze in Startup. I componenti che richiedono questi servizi vengono forniti tramite parametri del costruttore.

Controllers/MoviesController.cs Nel file il costruttore usa l'inserimento delle dipendenze per inserire il contesto del MvcMovieContext database nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Lo scaffolding ha generato il codice evidenziato seguente in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

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

Il sistema di configurazione ASP.NET Core legge il database "MvcMovieContext" stringa di connessione.

Esaminare il database generato stringa di connessione

Lo scaffolding ha aggiunto un stringa di connessione al appsettings.json file:

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

Per lo sviluppo locale, il sistema di configurazione ASP.NET Core legge la ConnectionString chiave dal appsettings.json file.

Classe InitialCreate

Esaminare il file di Migrations/{timestamp}_InitialCreate.cs migrazione:

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Movie",
            columns: table => new
            {
                Id = table.Column<int>(type: "int", nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Movie", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Movie");
    }
}

Nel codice precedente:

  • InitialCreate.Up crea la tabella Movie e configura Id come chiave primaria.
  • InitialCreate.Down ripristina le modifiche dello schema apportate dalla Up migrazione.

Inserimento delle dipendenze nel controller

Aprire il Controllers/MoviesController.cs file ed esaminare il costruttore:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Il costruttore usa l'inserimento dipendenze per inserire il contesto del database (MvcMovieContext) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Testare la pagina Create. Immettere e inviare i dati.

Testare le pagine Edit, Details e Delete.

Modelli fortemente tipizzati e direttiva @model

In un passaggio precedente di questa esercitazione è stato esaminato come un controller può passare oggetti o dati a una vista usando il dizionario ViewData. Il dizionario ViewData è un oggetto dinamico che fornisce un modo pratico ad associazione tardiva per passare informazioni a una vista.

MVC consente di passare oggetti modello fortemente tipizzati a una visualizzazione. Questo approccio fortemente tipizzato consente il controllo del codice in fase di compilazione. Il meccanismo di scaffolding ha passato un modello fortemente tipizzato nella classe e nelle MoviesController viste.

Esaminare il metodo generato Details nel Controllers/MoviesController.cs file:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

In genere il parametro id viene passato come dati di route. Ad esempio, https://localhost:5001/movies/details/1 imposta:

  • Il controller al movies controller, il primo segmento di URL.
  • Azione su details, il secondo segmento di URL.
  • Da id a 1, ultimo segmento di URL.

L'oggetto id può essere passato con una stringa di query, come nell'esempio seguente:

https://localhost:5001/movies/details?id=1

Il id parametro è definito come un tipo nullable (int?) nei casi in cui il id valore non viene specificato.

Un'espressione lambda viene passata al FirstOrDefaultAsync metodo per selezionare le entità film che corrispondono ai dati di route o al valore della stringa di query.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Se viene trovato un film, viene passata un'istanza del modello Movie alla vista Details:

return View(movie);

Esaminare il contenuto del Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

L'istruzione @model all'inizio del file di vista specifica il tipo di oggetto previsto dalla vista. Quando è stato creato il controller dei film, è stata inclusa l'istruzione @model seguente:

@model MvcMovie.Models.Movie

Questa direttiva @model consente di accedere al film che il controller ha passato alla vista. L'oggetto Model è fortemente tipizzato. Nella visualizzazione, ad esempio, Details.cshtml il codice passa ogni campo filmato agli DisplayNameFor helper HTML e DisplayFor con l'oggetto fortemente tipizzato Model . Le viste e i metodi Create e Edit passano anche un oggetto modello Movie.

Esaminare la Index.cshtml visualizzazione e il Index metodo nel controller Movies. Si noti che il codice crea un oggetto List quando chiama il metodo View. Il codice passa questo elenco Movies dal metodo di azione Index alla vista:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Quando è stato creato il controller movies, lo scaffolding includeva l'istruzione seguente @model all'inizio del Index.cshtml file:

@model IEnumerable<MvcMovie.Models.Movie>

La @model direttiva consente l'accesso all'elenco di film passati dal controller alla visualizzazione usando un Model oggetto fortemente tipizzato. Ad esempio, nella Index.cshtml visualizzazione il codice scorre i filmati con un'istruzione foreach sull'oggetto fortemente tipizzato Model :

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Poiché l'oggetto Model è fortemente tipizzato come IEnumerable<Movie> oggetto , ogni elemento del ciclo viene tipizzato come Movie. Tra gli altri vantaggi, il compilatore convalida i tipi usati nel codice.

Registrazione SQL di Entity Framework Core

La configurazione di registrazione viene comunemente fornita dalla sezione Logging dei file appsettings.{Environment}.json. Per registrare istruzioni SQL, aggiungere "Microsoft.EntityFrameworkCore.Database.Command": "Information" al appsettings.Development.json file:

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

Con il codice JSON precedente, le istruzioni SQL vengono visualizzate nella riga di comando e nella finestra di output di Visual Studio.

Per altre informazioni, vedere Registrazione in .NET Core e ASP.NET Core e questo problema di GitHub.

Risorse aggiuntive

In questa esercitazione vengono aggiunte classi per la gestione dei film in un database. Queste classi sono la parte "Model" dell'app MVC.

Queste classi di modello vengono usate con Entity Framework Core (EF Core) per lavorare con un database. EF Core è un framework ORM (Object-Relational Mapping) che semplifica il codice di accesso ai dati da scrivere.

Le classi di modello create sono note come classi POCO, da Plain Old CLR Objects. Le classi POCO non hanno alcuna dipendenza da EF Core. Definiscono solo le proprietà dei dati da archiviare nel database.

In questa esercitazione vengono create prima le classi di modelli e EF Core viene creato il database.

Aggiungere una classe del modello di dati

Fare clic con il pulsante destro del mouse sulla cartella >Modelli Aggiungi>classe. Denominare il file Movie.cs.

Aggiornare il Movie.cs file con il codice seguente:

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

La classe Movie contiene un campo Id, richiesto dal database per la chiave primaria.

L'attributo DataType su ReleaseDate specifica il tipo di dati (Date). Con questo attributo:

  • l'utente non deve immettere le informazioni temporali nel campo della data.
  • Viene visualizzata solo la data, non le informazioni temporali.

L'attributo DataAnnotations viene analizzato in un'esercitazione successiva.

Aggiungere i pacchetti NuGet di

Dal menu Strumenti scegliere Gestione pacchetti NuGet>Console di Gestione pacchetti.

Menu della Console di Gestione pacchetti

Nella console di Gestione pacchetti eseguire il comando seguente:

Install-Package Microsoft.EntityFrameworkCore.SqlServer

Il comando precedente aggiunge il EF Core provider SQL Server. Il pacchetto del provider installa il EF Core pacchetto come dipendenza. I pacchetti aggiuntivi vengono installati automaticamente nel passaggio di scaffolding più avanti nell'esercitazione.

Creare una classe di contesto di database

Per coordinare EF Core la funzionalità (Create, Read, Update, Delete) per il modello è necessaria una classe di contesto del Movie database. Il contesto del database è derivato da Microsoft.EntityFrameworkCore.DbContext e specifica le entità da includere nel modello di dati.

Creare una cartella Data.

Aggiungere un Data/MvcMovieContext.cs file con il codice seguente:

using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<Movie> Movie { get; set; }
    }
}

Il codice precedente crea una proprietà DbSet<Movie> per il set di entità. Nella terminologia di Entity Framework, un set di entità corrisponde in genere alla tabella di un database. Un'entità corrisponde a una riga nella tabella.

Registrare il contesto del database

ASP.NET Core viene compilato con l'inserimento di dipendenze. I servizi , ad esempio il contesto di database, devono essere registrati con l'inserimento delle dipendenze durante l'avvio EF Core dell'applicazione. I componenti che richiedono questi servizi (ad esempio Razor Pages) vengono forniti tramite parametri del costruttore. Più avanti nell'esercitazione viene illustrato il codice del costruttore che ottiene un'istanza del contesto di database. In questa sezione viene registrato il contesto di database per il contenitore di inserimento delle dipendenze.

Aggiungere le istruzioni seguenti using all'inizio di Startup.cs:

using MvcMovie.Data;
using Microsoft.EntityFrameworkCore;

Aggiungere il codice evidenziato seguente in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

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

Il nome della stringa di connessione viene passato al contesto chiamando un metodo in un oggetto DbContextOptions. Per lo sviluppo locale, il sistema di configurazione ASP.NET Core legge il stringa di connessione dal appsettings.json file.

Esaminare il stringa di connessione del database

Aggiungere un stringa di connessione al appsettings.json file:

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

Compilare il progetto per controllare se sono presenti errori del compilatore.

Eseguire lo scaffolding delle pagine Movie

Usare lo strumento di scaffolding per generare le pagine per le operazioni CRUD (creazione, lettura, aggiornamento ed eliminazione) per il modello Movie.

In Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella > Controllers Aggiungi > nuovo elemento con scaffolding.

vista del passaggio precedente

Nella finestra di dialogo Aggiungi scaffolding selezionare Controller MVC con visualizzazioni, usando Entity Framework > Aggiungi.

Finestra di dialogo Aggiungi scaffolding

Completare la finestra di dialogo Aggiungi controller:

  • Classe modello: Movie (MvcMovie.Models)
  • Classe contesto dati: MvcMovieContext (MvcMovie.Data)

Aggiungere il contesto dati

  • Viste: mantenere il valore predefinito di ogni opzione selezionata
  • Nome del controller: mantenere il valore predefinito MoviesController
  • Seleziona Aggiungi

Visual Studio crea:

  • Un controller di film (Controllers/MoviesController.cs)
  • Razor visualizzare i file per le pagine Create, Delete, Details, Edit e Index (*Views/Movies/'.cshtml')

La creazione automatica di questi file è nota come scaffolding.

Non è possibile usare ancora le pagine sottoposte a scaffolding perché il database non esiste. Se si esegue l'app e si fa clic sul collegamento Movie App , si ottiene un impossibile aprire il database o nessuna di queste tabelle: messaggio di errore movie .

Migrazione iniziale

Usare la EF Corefunzionalità Migrazioni per creare il database. Migrazioni è un set di strumenti che consentono di creare e aggiornare un database in modo che corrisponda al modello di dati.

Dal menu Strumenti scegliere Gestione pacchetti NuGet>Console di Gestione pacchetti.

Nella Console di Gestione pacchetti immettere i comandi seguenti:

Add-Migration InitialCreate
Update-Database
  • Add-Migration InitialCreate: genera un Migrations/{timestamp}_InitialCreate.cs file di migrazione. L'argomento InitialCreate è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext.

  • Update-Database: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up metodo nel Migrations/{time-stamp}_InitialCreate.cs file , che crea il database.

    Il comando database update genera l'avviso seguente:

    No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').

    È possibile ignorare tale avviso. Verrà risolto in un'esercitazione successiva.

Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.

Classe InitialCreate

Esaminare il file di Migrations/{timestamp}_InitialCreate.cs migrazione:

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Movie",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", 
                                 SqlServerValueGenerationStrategy.IdentityColumn),
                Title = table.Column<string>(nullable: true),
                ReleaseDate = table.Column<DateTime>(nullable: false),
                Genre = table.Column<string>(nullable: true),
                Price = table.Column<decimal>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Movie", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Movie");
    }
}

Il metodo Up crea la tabella Movie e configura Id come chiave primaria. Il metodo Down annulla le modifiche dello schema apportate dalla migrazione Up.

Testare l'app

  • Eseguire l'app e fare clic sul collegamento Movie App.

    Se si ottiene un'eccezione simile a una delle seguenti:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Probabilmente non è stato eseguito il passaggio delle migrazioni.

  • Testare la pagina Create. Immettere e inviare i dati.

    Nota

    Potrebbe non essere possibile immettere virgole decimali nel campo Price. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese (Stati Uniti), è necessario localizzare l'app. Per istruzioni sulla localizzazione, vedere questo problema su GitHub.

  • Testare le pagine Edit, Details e Delete.

Inserimento delle dipendenze nel controller

Aprire il Controllers/MoviesController.cs file ed esaminare il costruttore:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Il costruttore usa l'inserimento dipendenze per inserire il contesto del database (MvcMovieContext) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.

Modelli fortemente tipizzati e parola chiave @model

In un passaggio precedente di questa esercitazione è stato esaminato come un controller può passare oggetti o dati a una vista usando il dizionario ViewData. Il dizionario ViewData è un oggetto dinamico che fornisce un modo pratico ad associazione tardiva per passare informazioni a una vista.

MVC consente anche di passare oggetti modello fortemente tipizzati a una vista. Questo approccio fortemente tipizzato consente il controllo del codice in fase di compilazione. Con il meccanismo di scaffolding è stato usato questo approccio, ovvero il passaggio di un modello fortemente tipizzato, con le viste e la classe MoviesController.

Esaminare il metodo generato Details nel Controllers/MoviesController.cs file:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

In genere il parametro id viene passato come dati di route. Ad esempio https://localhost:5001/movies/details/1 imposta:

  • Il controller sul controller movies (primo segmento di URL).
  • L'azione su details (secondo segmento di URL).
  • L'ID su 1 (ultimo segmento di URL).

È possibile anche passare id con una stringa di query nel modo seguente:

https://localhost:5001/movies/details?id=1

Il parametro id viene definito come tipo nullable (int?) nel caso in cui non venga fornito un valore ID.

Un'espressione lambda viene passata a FirstOrDefaultAsync per selezionare le entità film che corrispondono al valore della stringa di query o dei dati di route.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Se viene trovato un film, viene passata un'istanza del modello Movie alla vista Details:

return View(movie);

Esaminare il contenuto del Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

L'istruzione @model all'inizio del file di vista specifica il tipo di oggetto previsto dalla vista. Quando è stato creato il controller dei film, è stata inclusa l'istruzione @model seguente:

@model MvcMovie.Models.Movie

Questa direttiva @model consente di accedere al film che il controller ha passato alla vista. L'oggetto Model è fortemente tipizzato. Nella visualizzazione, ad esempio, Details.cshtml il codice passa ogni campo filmato agli DisplayNameFor helper HTML e DisplayFor con l'oggetto fortemente tipizzato Model . Le viste e i metodi Create e Edit passano anche un oggetto modello Movie.

Esaminare la Index.cshtml visualizzazione e il Index metodo nel controller Movies. Si noti che il codice crea un oggetto List quando chiama il metodo View. Il codice passa questo elenco Movies dal metodo di azione Index alla vista:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Quando è stato creato il controller movies, lo scaffolding includeva l'istruzione seguente @model all'inizio del Index.cshtml file:

@model IEnumerable<MvcMovie.Models.Movie>

La direttiva @model consente di accedere all'elenco di film che il controller ha passato alla vista usando un oggetto Model fortemente tipizzato. Ad esempio, nella Index.cshtml visualizzazione il codice scorre i filmati con un'istruzione foreach sull'oggetto fortemente tipizzato Model :

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Poiché l'oggetto Model è fortemente tipizzato (come un oggetto IEnumerable<Movie>), ogni elemento nel ciclo viene tipizzato come Movie. Tra gli altri vantaggi, si ottiene un controllo del codice in fase di compilazione.

Risorse aggiuntive