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 Create
pagine , Read
, Update
e 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.
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.
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.
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 unMigrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomentoInitialCreate
è 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 classeMvcMovieContext
.
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 ilUp
metodo nelMigrations/{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 configuraId
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dallaUp
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 Create
pagine , Read
, Update
e 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.
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.
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.
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 unMigrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomentoInitialCreate
è 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 classeMvcMovieContext
.Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue ilUp
metodo nelMigrations/{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 configuraId
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dallaUp
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 Create
pagine , Read
, Update
e 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.
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.
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.
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 unMigrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomentoInitialCreate
è 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 classeMvcMovieContext
.Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue ilUp
metodo nelMigrations/{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 configuraId
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dallaUp
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.
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 Create
pagine , Read
, Update
e 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.
Nella finestra di dialogo Aggiungi scaffolding selezionare Controller MVC con visualizzazioni, usando Entity Framework > Aggiungi.
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.
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 unMigrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomentoInitialCreate
è 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 classeMvcMovieContext
.Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue ilUp
metodo nelMigrations/{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 configuraId
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dallaUp
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.
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 Create
pagine , Read
, Update
e 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.
Nella finestra di dialogo Aggiungi scaffolding selezionare Controller MVC con visualizzazioni, usando Entity Framework > Aggiungi.
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.
Lo scaffolding aggiorna quanto segue:
- Inserisce i riferimenti necessari al pacchetto nel file di
MvcMovie.csproj
progetto. - Registra il contesto del
Startup.cs
database nelStartup.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 unMigrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomentoInitialCreate
è 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 classeMvcMovieContext
.Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue ilUp
metodo nelMigrations/{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 configuraId
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dallaUp
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.
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.
Nella finestra di dialogo Aggiungi scaffolding selezionare Controller MVC con visualizzazioni, usando Entity Framework > Aggiungi.
Completare la finestra di dialogo Aggiungi controller:
- Classe modello: Movie (MvcMovie.Models)
- Classe contesto dati: MvcMovieContext (MvcMovie.Data)
- 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 unMigrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomentoInitialCreate
è 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 classeMvcMovieContext
.Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue ilUp
metodo nelMigrations/{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.