Eventi
Campionati mondiali di Power BI DataViz
14 feb, 16 - 31 mar, 16
Con 4 possibilità di entrare, si potrebbe vincere un pacchetto conferenza e renderlo al Live Grand Finale a Las Vegas
Altre informazioniQuesto browser non è più supportato.
Esegui l'aggiornamento a Microsoft Edge per sfruttare i vantaggi di funzionalità più recenti, aggiornamenti della sicurezza e supporto tecnico.
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 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 9 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.
Fare clic con il pulsante destro del mouse sulla >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'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.
Visual Studio installa automaticamente i pacchetti necessari.
Compilare il progetto per controllare se sono presenti errori del compilatore.
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:
Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :
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:
Controllers/MoviesController.cs
Views/Movies/*.cshtml
Data/MvcMovieContext.cs
Lo scaffolding aggiorna quanto segue:
MvcMovie.csproj
progetto.Program.cs
file.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.
Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.
Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.
Nella console Gestione pacchetti immettere il comando seguente:
Add-Migration InitialCreate
Add-Migration InitialCreate
: genera un Migrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomento InitialCreate
è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext
.Viene visualizzato l'avviso seguente, risolto in un passaggio successivo:
Non è stato specificato alcun tipo di archivio per la proprietà decimale 'Price' nel tipo di entità 'Movie'. This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Specificare in modo esplicito il tipo di colonna di SQL Server in grado di contenere tutti i valori in 'OnModelCreating' usando 'HasColumnType', specificare precisione e scala usando 'HasPrecision' o configurare un convertitore di valori con 'HasConversion'.
In PMC immettere il comando seguente:
Update-Database
Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up
metodo nel Migrations/{time-stamp}_InitialCreate.cs
file , che crea il database.Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.
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.
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.
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.
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.
Esaminare il file di Migrations/{timestamp}_InitialCreate.cs
migrazione:
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MvcMovie.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Movie",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Movie", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Movie");
}
}
}
Nel codice precedente:
InitialCreate.Up
crea la tabella Movie e configura Id
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dalla Up
migrazione.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.
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:
movies
controller, il primo segmento di URL.details
, il secondo segmento di URL.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.
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.
Fare clic con il pulsante destro del mouse sulla >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'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.
Visual Studio installa automaticamente i pacchetti necessari.
Compilare il progetto per controllare se sono presenti errori del compilatore.
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:
Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :
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:
Controllers/MoviesController.cs
Views/Movies/*.cshtml
Data/MvcMovieContext.cs
Lo scaffolding aggiorna quanto segue:
MvcMovie.csproj
progetto.Program.cs
file.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.
Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.
Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.
Nella console di Gestione pacchetti immettere i comandi seguenti:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: genera un Migrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomento InitialCreate
è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext
.
Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up
metodo nel Migrations/{time-stamp}_InitialCreate.cs
file , che crea il database.
Il Update-Database
comando genera l'avviso seguente:
Non è stato specificato alcun tipo di archivio per la proprietà decimale 'Price' nel tipo di entità 'Movie'. This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Specificare in modo esplicito il tipo di colonna di SQL Server in grado di contenere tutti i valori in 'OnModelCreating' usando 'HasColumnType', specificare precisione e scala usando 'HasPrecision' o configurare un convertitore di valori con 'HasConversion'.
Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.
Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.
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.
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.
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.
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.
Esaminare il file di Migrations/{timestamp}_InitialCreate.cs
migrazione:
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MvcMovie.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Movie",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Movie", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Movie");
}
}
}
Nel codice precedente:
InitialCreate.Up
crea la tabella Movie e configura Id
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dalla Up
migrazione.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.
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:
movies
controller, il primo segmento di URL.details
, il secondo segmento di URL.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.
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.
Fare clic con il pulsante destro del mouse sulla >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'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.
Visual Studio installa automaticamente i pacchetti necessari.
Compilare il progetto per controllare se sono presenti errori del compilatore.
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:
Completare la finestra di dialogo Aggiungi controller MVC con visualizzazioni usando Entity Framework :
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:
Controllers/MoviesController.cs
Views/Movies/*.cshtml
Data/MvcMovieContext.cs
Lo scaffolding aggiorna quanto segue:
MvcMovie.csproj
progetto.Program.cs
file.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.
Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.
Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.
Nella console di Gestione pacchetti immettere i comandi seguenti:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: genera un Migrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomento InitialCreate
è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext
.
Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up
metodo nel Migrations/{time-stamp}_InitialCreate.cs
file , che crea il database.
Il Update-Database
comando genera l'avviso seguente:
No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').
Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.
Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.
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.
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.
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.
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.
Esaminare il file di Migrations/{timestamp}_InitialCreate.cs
migrazione:
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MvcMovie.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Movie",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Movie", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Movie");
}
}
}
Nel codice precedente:
InitialCreate.Up
crea la tabella Movie e configura Id
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dalla Up
migrazione.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.
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:
movies
controller, il primo segmento di URL.details
, il secondo segmento di URL.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.
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.
Fare clic con il pulsante destro del mouse sulla >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'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.
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:
Compilare il progetto per controllare se sono presenti errori del compilatore.
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 :
Se viene visualizzato un messaggio di errore, selezionare Aggiungi una seconda volta per riprovare.
Lo scaffolding aggiorna quanto segue:
MvcMovie.csproj
progetto.Program.cs
file.appsettings.json
file.Lo scaffolding crea quanto segue:
Controllers/MoviesController.cs
Views/Movies/*.cshtml
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.
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.
Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.
Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.
Nella console di Gestione pacchetti immettere i comandi seguenti:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: genera un Migrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomento InitialCreate
è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext
.
Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up
metodo nel Migrations/{time-stamp}_InitialCreate.cs
file , che crea il database.
Il Update-Database
comando genera l'avviso seguente:
No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').
Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.
Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.
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.
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.
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.
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.
Esaminare il file di Migrations/{timestamp}_InitialCreate.cs
migrazione:
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MvcMovie.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Movie",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Movie", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Movie");
}
}
}
Nel codice precedente:
InitialCreate.Up
crea la tabella Movie e configura Id
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dalla Up
migrazione.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.
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:
movies
controller, il primo segmento di URL.details
, il secondo segmento di URL.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.
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.
Fare clic con il pulsante destro del mouse sulla >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'attributo DataAnnotations viene analizzato in un'esercitazione successiva.
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:
Compilare il progetto per controllare se sono presenti errori del compilatore.
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 :
Lo scaffolding aggiorna quanto segue:
MvcMovie.csproj
progetto.Startup.ConfigureServices
database nel Startup.cs
file.appsettings.json
file.Lo scaffolding crea quanto segue:
Controllers/MoviesController.cs
Views/Movies/*.cshtml
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.
Usare la EF Corefunzionalità Migrazioni per creare il database. Le migrazioni sono un set di strumenti che creano e aggiornano un database in modo che corrispondano al modello di dati.
Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.
Nella console di Gestione pacchetti immettere i comandi seguenti:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: genera un Migrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomento InitialCreate
è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext
.
Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up
metodo nel Migrations/{time-stamp}_InitialCreate.cs
file , che crea il database.
Il Update-Database
comando genera l'avviso seguente:
No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').
Ignorare l'avviso precedente, che viene risolto in un'esercitazione successiva.
Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.
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.
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.
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.
Esaminare il file di Migrations/{timestamp}_InitialCreate.cs
migrazione:
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Movie",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Movie", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Movie");
}
}
Nel codice precedente:
InitialCreate.Up
crea la tabella Movie e configura Id
come chiave primaria.InitialCreate.Down
ripristina le modifiche dello schema apportate dalla Up
migrazione.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.
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:
movies
controller, il primo segmento di URL.details
, il secondo segmento di URL.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.
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.
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.
Fare clic con il pulsante destro del mouse sulla >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'attributo DataAnnotations viene analizzato in un'esercitazione successiva.
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.
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.
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.
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.
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 > 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:
Visual Studio crea:
Controllers/MoviesController.cs
)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 .
Usare la EF Corefunzionalità Migrazioni per creare il database. Migrazioni è un set di strumenti che consentono di creare e aggiornare un database in modo che corrisponda al modello di dati.
Dal menu Strumenti scegliere Gestione pacchetti NuGet>Console di Gestione pacchetti.
Nella Console di Gestione pacchetti immettere i comandi seguenti:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: genera un Migrations/{timestamp}_InitialCreate.cs
file di migrazione. L'argomento InitialCreate
è il nome della migrazione. È possibile usare qualsiasi nome, ma per convenzione viene selezionato un nome che descrive la migrazione. Trattandosi della prima migrazione, la classe generata contiene il codice per creare lo schema del database. Lo schema del database si basa sul modello specificato nella classe MvcMovieContext
.
Update-Database
: aggiorna il database alla migrazione più recente, creata dal comando precedente. Questo comando esegue il Up
metodo nel Migrations/{time-stamp}_InitialCreate.cs
file , che crea il database.
Il comando database update genera l'avviso seguente:
No type was specified for the decimal column 'Price' on entity type 'Movie'. (Nessun tipo specificato per la colonna decimale 'Price' nel tipo di entità 'Movie'). This will cause values to be silently truncated if they do not fit in the default precision and scale. (I valori saranno quindi automaticamente troncati se non rispettano la precisione e la scala predefinite). Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'. (Specificare in modo esplicito il tipo di colonna di SQL Server che può supportare tutti i valori usando 'HasColumnType()').
È possibile ignorare tale avviso. Verrà risolto in un'esercitazione successiva.
Per altre informazioni sugli strumenti PMC per EF Core, vedere EF Core le informazioni di riferimento sugli strumenti - PMC in Visual Studio.
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
.
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.
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.
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:
movies
(primo segmento di URL).details
(secondo 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.
Feedback su ASP.NET Core
ASP.NET Core è un progetto di open source. Selezionare un collegamento per fornire feedback:
Eventi
Campionati mondiali di Power BI DataViz
14 feb, 16 - 31 mar, 16
Con 4 possibilità di entrare, si potrebbe vincere un pacchetto conferenza e renderlo al Live Grand Finale a Las Vegas
Altre informazioniFormazione
Modulo
Creare un'interfaccia utente Web con ASP.NET Core - Training
Informazioni su come creare pagine Web usando Razor con ASP.NET Core.
Documentazione
Parte 5, usare un database in un'app ASP.NET Core MVC
Parte 5 della serie di esercitazioni su ASP.NET Core MVC.
Parte 3, aggiungere una visualizzazione a un'app MVC core ASP.NET
Parte 3 della serie di esercitazioni su ASP.NET Core MVC.
Parte 6, metodi e visualizzazioni del controller in ASP.NET Core
Parte 6, aggiungere un modello a un'app MVC core ASP.NET