Partie 4, ajouter un modèle dans une application ASP.NET Core MVC

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 9 de cet article.

Par Rick Anderson et Jon P Smith.

Dans ce tutoriel, des classes sont ajoutées pour la gestion des films dans une base de données. Ces classes constituent la partie « Modèle » de l’application MVC.

Ces classes de modèle sont utilisées avec Entity Framework Core (EF Core) pour utiliser une base de données. EF Core est une infrastructure de mappage relationnel d’objets qui simplifie le code d’accès aux données à écrire.

Les classes du modèle créées sont appelées classes POCO, à partir de Plain Old CLR Objects. Les classes POCO n’ont aucune dépendance vis-à-vis de EF Core. Elles définissent uniquement les propriétés des données qui seront stockées dans la base de données.

Dans ce tutoriel, les classes du modèle sont d’abord créées, puis EF Core crée la base de données.

Ajouter une classe de modèle de données

Cliquez avec le bouton droit sur le dossier Modèles >Ajouter>Classe. Nommez le fichier Movie.cs.

Mettez à jour le fichier Models/Movie.cs avec le code suivant :

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 contient un champ Id, qui est nécessaire à la base de données pour la clé primaire.

L’attribut DataType de ReleaseDate spécifie le type de données (Date). Avec cet attribut :

  • L’utilisateur n’est pas obligé d’entrer les informations de temps dans le champ de date.
  • Seule la date est affichée, pas les informations de temps.

Les DataAnnotations sont traitées dans un prochain didacticiel.

La présence du point d’interrogation après string indique que la propriété peut accepter les valeurs Null. Pour plus d’informations, consultez Types référence pouvant accepter la valeur Null.

Ajouter des packages NuGet

Visual Studio installe automatiquement les packages requis.

Générez le projet en tant que vérification des erreurs du compilateur.

Générer automatiquement des pages de film

Utilisez l’outil de génération de modèles automatique pour Create, Read, Update, et Delete des pages du modèle de film.

Cliquez avec le bouton droit sur le dossier Contrôleurs dans l’Explorateur de solutions, puis sélectionnez Ajouter > Nouvel élément généré automatiquement.

affichage de l’étape ci-dessus

Dans la boîte de dialogue Ajouter un nouvel élément de modèle généré automatiquement :

  • Dans le volet gauche, sélectionnez Installé>Communes>MVC.
  • Sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework.
  • Sélectionnez Ajouter.

Boîte de dialogue Ajouter un modèle automatique

Terminez la boîte de dialogue Ajouter un contrôleur MVC avec des vues, à l’aide d’Entity Framework :

  • Dans la liste déroulante Classe du modèle, sélectionnez Film (MvcMovie.Models).
  • Dans la ligne Classe du contexte de données, sélectionnez le signe + (plus).
    • Dans la boîte de dialogue Ajouter un contexte de données, le nom de classe MvcMovie.Data.MvcMovieContext est généré.
    • Cliquez sur Ajouter.
  • Dans la liste déroulante Fournisseur de base de données, sélectionnez SQL Server.
  • Vues et Nom du contrôleur : conservez la valeur par défaut.
  • Sélectionnez Ajouter.

Ajouter un contexte de données – conserver les valeurs par défaut

Si vous obtenez un message d’erreur, sélectionnez Ajouter une deuxième fois pour réessayer.

La génération de modèles automatique ajoute les packages suivants :

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

La génération automatique crée les éléments suivants :

  • Un contrôleur de films : Controllers/MoviesController.cs
  • Razor afficher les fichiers pour les pages Créer, Supprimer, Détails, Modifier et Indexer : Views/Movies/*.cshtml
  • Une classe de contexte de base de données : Data/MvcMovieContext.cs

La génération de modèles automatique met à jour les éléments suivants :

  • Insère les références de package requises dans le fichier projet MvcMovie.csproj.
  • Inscrit le contexte de base de données dans le fichier Program.cs.
  • Ajoute une chaîne de connexion de base de données au fichier appsettings.json.

La création automatique de ces fichiers et mises à jour est appelée génération de modèles automatique.

Les pages générées automatiquement ne peuvent pas encore être utilisées, car la base de données n’existe pas. L’exécution de l’application et la sélection du lien Application vidéo entraînent un message d’erreur Impossible d’ouvrir la base de données ou Le type de table suivant n’existe pas : Film.

Générez l’application pour vérifier qu’il n’y a pas d’erreurs.

Migration initiale

Utilisez la fonctionnalité EF CoreMigrations pour créer la base de données. La fonctionnalité Migrations est un ensemble d’outils qui vous permettent de créer et de mettre à jour une base de données pour qu’elle corresponde à votre modèle de données.

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package.

Dans la console du Gestionnaire de package (PMC), entrez la commande suivante :

Add-Migration InitialCreate

  • Add-Migration InitialCreate: Génère un Migrations/{timestamp}_InitialCreate.cs fichier de migration. L’argument InitialCreate est le nom de la migration. Vous pouvez utiliser n’importe quel nom, mais par convention, un nom décrivant la migration est sélectionné. Étant donné qu’il s’agit de la première migration, la classe générée contient du code permettant de créer le schéma de la base de données. Le schéma de base de données est basé sur le modèle spécifié dans la classe MvcMovieContext.

L’avertissement suivant s’affiche et sera traité dans une étape ultérieure :

Aucun type de magasin n’a été spécifié pour la propriété décimale « Price » sur le type d’entité « Movie ». Les valeurs sont tronquées en mode silencieux si elles ne sont pas compatibles avec la précision et l’échelle par défaut. Spécifiez explicitement le type de colonne SQL Server qui peut prendre en charge toutes les valeurs dans « OnModelCreating » à l’aide de « HasColumnType », spécifiez la précision et l’échelle à l’aide de « HasPrecision » ou configurez un convertisseur de valeurs à l’aide de « HasConversion ».

Dans la console PMC, entrez la commande suivante :

Update-Database

  • Update-Database : Met à jour la base de données vers la dernière migration, qui a été créée par la commande précédente. Cette commande exécute la méthode Up dans le fichier Migrations/{time-stamp}_InitialCreate.cs, qui crée la base de données.

Pour plus d’informations sur les outils de la console du gestionnaire de package pour EF Core, consultez EF Core référence sur les outils - Console du gestionnaire de package dans Visual Studio.

Tester l’application

Exécutez l’application et sélectionnez sur le lien Movie App.

Si vous obtenez une exception semblable à ce qui suit, vous avez peut-être manqué la commande Update-Database à l’étape des migrations :

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

Remarque

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que « Anglais » qui utilisent une virgule (« , ») comme décimale et des formats de date autres que le format « Anglais (États-Unis »), l’application doit être localisée. Pour obtenir des instructions sur la localisation, consultez ce problème GitHub.

Examinez la classe de contexte de base de données générée et l’inscription

Avec EF Core, l’accès aux données est effectué à l’aide d’un modèle. Un modèle est constitué de classes d’entité et d’un objet de contexte qui représente une session avec la base de données. L’objet de contexte permet l’interrogation et l’enregistrement des données. Le contexte de base de données est dérivé de Microsoft.EntityFrameworkCore.DbContext et il spécifie les entités à inclure dans le modèle de données.

La génération de modèles crée la classe Data/MvcMovieContext.cs de contexte de base de données :

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!;
    }
}

Le code précédent crée une propriété DbSet<Movie> qui représente les films dans la base de données.

Injection de dépendances

ASP.NET Core comprend l’injection de dépendances (DI). Les services, tels que le contexte de base de données, sont inscrits avec une injection de dépendance dans Program.cs. Ces services sont fournis aux composants qui en ont besoin via des paramètres de constructeur.

Dans le fichier Controllers/MoviesController.cs, le constructeur utilise une injection de dépendance pour injecter le contexte de base de données MvcMovieContext dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

La génération de modèles a généré le code en surbrillance suivant dans 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.")));

Le système de configuration ASP.NET Core lit la chaîne de connexion de base de données « MvcMovieContext ».

Examinez la chaîne de connexion de base de données générée

La génération de modèles a ajouté une chaîne de connexion au fichier appsettings.json :

{
  "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"
  }
}

Pour le développement local, le système de configuration ASP.NET Core lit la clé ConnectionString depuis le fichier appsettings.json.

La classe InitialCreate

Examinez le fichier de migration Migrations/{timestamp}_InitialCreate.cs :

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");
        }
    }
}

Dans le code précédent :

  • La méthode InitialCreate.Up crée la table Film et configure Id comme la clé primaire.
  • InitialCreate.Down rétablit les modifications de schéma provoquées par la migration Up.

Injection de dépendances dans le contrôleur

Ouvrez le fichier Controllers/MoviesController.cs et examinez le constructeur :

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Le constructeur utilise une injection de dépendance pour injecter le contexte de base de données (MvcMovieContext) dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

Testez la page Create. Entrez et envoyez des données.

Testez les pages Edit, Details et Delete.

Modèles fortement typés et directive @model

Plus tôt dans ce didacticiel, vous avez vu comment un contrôleur peut passer des données ou des objets à une vue en utilisant le dictionnaire ViewData. Le dictionnaire ViewData est un objet dynamique qui fournit un moyen pratique d’effectuer une liaison tardive pour passer des informations à une vue.

Le modèle MVC fournit la possibilité de passer des objets de modèle fortement typés à une vue. Cette approche fortement typée permet de vérifier votre code au moment de la compilation. Le mécanisme de génération de modèles a passé un modèle fortement typé dans la classe et les vues MoviesController.

Examinez la méthode Details générée dans le fichier Controllers/MoviesController.cs :

// 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);
}

Le paramètre id est généralement passé en tant que données de routage. Par exemple, https://localhost:5001/movies/details/1 définit :

  • Le contrôleur sur le contrôleur movies, le premier segment de l’URL.
  • L’action sur details, le deuxième segment de l’URL.
  • Le id à 1, le dernier segment d’URL.

Le id peut être transmis avec une chaîne de requête, comme dans l’exemple suivant :

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

Le paramètre id est défini comme type Nullable (int?) au cas où la valeur id n’est pas fournie.

Une expression lambda est passée à la méthode FirstOrDefaultAsync pour sélectionner les entités de film qui correspondent aux données de routage ou à la valeur de la chaîne de requête.

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

Si un film est trouvé, une instance du modèle Movie est passée à la vue Details :

return View(movie);

Examinez le contenu du fichier Views/Movies/Details.cshtml :

@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’instruction @model située en haut du fichier de la vue spécifie le type d’objet attendu par la vue. Lorsque le contrôleur de film était créé, l’instruction @model suivante était incluse :

@model MvcMovie.Models.Movie

Cette directive @model autorise l’accès au film que le contrôleur a passé à la vue. L’objet Model est fortement typé. Par exemple, dans la vue Details.cshtml, le code passe chaque champ du film aux Helpers HTML DisplayNameFor et DisplayFor avec l’objet Model fortement typé. Les méthodes et les vues Create et Edit passent aussi un objet du modèle Movie.

Examinez la vue Index.cshtml et la méthode Index dans le contrôleur Movies. Notez comment le code crée un objet List quand il appelle la méthode View. Le code passe cette liste Movies de la méthode d’action Index à la vue :

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

Le code retourne les détails du problème si la propriété Movie du contexte de données est null.

Lors de la création du contrôleur du film, la génération de modèles automatique a inclus l’instruction @model suivante en haut du fichier Index.cshtml :

@model IEnumerable<MvcMovie.Models.Movie>

La directive @model permet d’accéder à la liste des films que le contrôleur a passé à la vue en utilisant un objet Model qui est fortement typé. Par exemple, dans la vue Index.cshtml, le code boucle dans les films avec une instruction foreach sur l’objet Model fortement typé :

@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>

Comme l’objet Model est fortement typé en tant qu’objet IEnumerable<Movie>, chaque élément de la boucle est typé en tant que Movie. Entre autres avantages, le compilateur valide les types utilisés dans le code.

Ressources supplémentaires

Dans ce tutoriel, des classes sont ajoutées pour la gestion des films dans une base de données. Ces classes constituent la partie « Modèle » de l’application MVC.

Ces classes de modèle sont utilisées avec Entity Framework Core (EF Core) pour utiliser une base de données. EF Core est une infrastructure de mappage relationnel d’objets qui simplifie le code d’accès aux données à écrire.

Les classes du modèle créées sont appelées classes POCO, à partir de Plain Old CLR Objects. Les classes POCO n’ont aucune dépendance vis-à-vis de EF Core. Elles définissent uniquement les propriétés des données qui seront stockées dans la base de données.

Dans ce tutoriel, les classes du modèle sont d’abord créées, puis EF Core crée la base de données.

Ajouter une classe de modèle de données

Cliquez avec le bouton droit sur le dossier Modèles >Ajouter>Classe. Nommez le fichier Movie.cs.

Mettez à jour le fichier Models/Movie.cs avec le code suivant :

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 contient un champ Id, qui est nécessaire à la base de données pour la clé primaire.

L’attribut DataType de ReleaseDate spécifie le type de données (Date). Avec cet attribut :

  • L’utilisateur n’est pas obligé d’entrer les informations de temps dans le champ de date.
  • Seule la date est affichée, pas les informations de temps.

Les DataAnnotations sont traitées dans un prochain didacticiel.

La présence du point d’interrogation après string indique que la propriété peut accepter les valeurs Null. Pour plus d’informations, consultez Types référence pouvant accepter la valeur Null.

Ajouter des packages NuGet

Visual Studio installe automatiquement les packages requis.

Générez le projet en tant que vérification des erreurs du compilateur.

Générer automatiquement des pages de film

Utilisez l’outil de génération de modèles automatique pour Create, Read, Update, et Delete des pages du modèle de film.

Cliquez avec le bouton droit sur le dossier Contrôleurs dans l’Explorateur de solutions, puis sélectionnez Ajouter > Nouvel élément généré automatiquement.

affichage de l’étape ci-dessus

Dans la boîte de dialogue Ajouter un nouvel élément de modèle généré automatiquement :

  • Dans le volet gauche, sélectionnez Installé>Communes>MVC.
  • Sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework.
  • Sélectionnez Ajouter.

Boîte de dialogue Ajouter un modèle automatique

Terminez la boîte de dialogue Ajouter un contrôleur MVC avec des vues, à l’aide d’Entity Framework :

  • Dans la liste déroulante Classe du modèle, sélectionnez Film (MvcMovie.Models).
  • Dans la ligne Classe du contexte de données, sélectionnez le signe + (plus).
    • Dans la boîte de dialogue Ajouter un contexte de données, le nom de classe MvcMovie.Data.MvcMovieContext est généré.
    • Cliquez sur Ajouter.
  • Dans la liste déroulante Fournisseur de base de données, sélectionnez SQL Server.
  • Vues et Nom du contrôleur : conservez la valeur par défaut.
  • Sélectionnez Ajouter.

Ajouter un contexte de données – conserver les valeurs par défaut

Si vous obtenez un message d’erreur, sélectionnez Ajouter une deuxième fois pour réessayer.

La génération de modèles automatique ajoute les packages suivants :

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

La génération automatique crée les éléments suivants :

  • Un contrôleur de films : Controllers/MoviesController.cs
  • Razor afficher les fichiers pour les pages Créer, Supprimer, Détails, Modifier et Indexer : Views/Movies/*.cshtml
  • Une classe de contexte de base de données : Data/MvcMovieContext.cs

La génération de modèles automatique met à jour les éléments suivants :

  • Insère les références de package requises dans le fichier projet MvcMovie.csproj.
  • Inscrit le contexte de base de données dans le fichier Program.cs.
  • Ajoute une chaîne de connexion de base de données au fichier appsettings.json.

La création automatique de ces fichiers et mises à jour est appelée génération de modèles automatique.

Les pages générées automatiquement ne peuvent pas encore être utilisées, car la base de données n’existe pas. L’exécution de l’application et la sélection du lien Application vidéo entraînent un message d’erreur Impossible d’ouvrir la base de données ou Le type de table suivant n’existe pas : Film.

Générez l’application pour vérifier qu’il n’y a pas d’erreurs.

Migration initiale

Utilisez la fonctionnalité EF CoreMigrations pour créer la base de données. La fonctionnalité Migrations est un ensemble d’outils qui vous permettent de créer et de mettre à jour une base de données pour qu’elle corresponde à votre modèle de données.

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package.

Dans la console du Gestionnaire de package, entrez les commandes suivantes :

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Génère un fichier de migration Migrations/{timestamp}_InitialCreate.cs. L’argument InitialCreate est le nom de la migration. Vous pouvez utiliser n’importe quel nom, mais par convention, un nom décrivant la migration est sélectionné. Étant donné qu’il s’agit de la première migration, la classe générée contient du code permettant de créer le schéma de la base de données. Le schéma de base de données est basé sur le modèle spécifié dans la classe MvcMovieContext.

  • Update-Database : Met à jour la base de données vers la dernière migration, qui a été créée par la commande précédente. Cette commande exécute la méthode Up dans le fichier Migrations/{time-stamp}_InitialCreate.cs, qui crée la base de données.

La commande Update-Database génère l’avertissement suivant :

Aucun type de magasin n’a été spécifié pour la propriété décimale « Price » sur le type d’entité « Movie ». Les valeurs sont tronquées en mode silencieux si elles ne sont pas compatibles avec la précision et l’échelle par défaut. Spécifiez explicitement le type de colonne SQL Server qui peut prendre en charge toutes les valeurs dans « OnModelCreating » à l’aide de « HasColumnType », spécifiez la précision et l’échelle à l’aide de « HasPrecision » ou configurez un convertisseur de valeurs à l’aide de « HasConversion ».

Ignorez l’avertissement précédent, il est résolu dans un tutoriel ultérieur.

Pour plus d’informations sur les outils de la console du gestionnaire de package pour EF Core, consultez EF Core référence sur les outils - Console du gestionnaire de package dans Visual Studio.

Tester l’application

Exécutez l’application et sélectionnez sur le lien Movie App.

Si vous obtenez une exception semblable à ce qui suit, vous avez peut-être manqué la commande Update-Database à l’étape des migrations :

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

Remarque

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que « Anglais » qui utilisent une virgule (« , ») comme décimale et des formats de date autres que le format « Anglais (États-Unis »), l’application doit être localisée. Pour obtenir des instructions sur la localisation, consultez ce problème GitHub.

Examinez la classe de contexte de base de données générée et l’inscription

Avec EF Core, l’accès aux données est effectué à l’aide d’un modèle. Un modèle est constitué de classes d’entité et d’un objet de contexte qui représente une session avec la base de données. L’objet de contexte permet l’interrogation et l’enregistrement des données. Le contexte de base de données est dérivé de Microsoft.EntityFrameworkCore.DbContext et il spécifie les entités à inclure dans le modèle de données.

La génération de modèles crée la classe Data/MvcMovieContext.cs de contexte de base de données :

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; }
    }
}

Le code précédent crée une propriété DbSet<Movie> qui représente les films dans la base de données.

Injection de dépendances

ASP.NET Core comprend l’injection de dépendances (DI). Les services, tels que le contexte de base de données, sont inscrits avec une injection de dépendance dans Program.cs. Ces services sont fournis aux composants qui en ont besoin via des paramètres de constructeur.

Dans le fichier Controllers/MoviesController.cs, le constructeur utilise une injection de dépendance pour injecter le contexte de base de données MvcMovieContext dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

La génération de modèles a généré le code en surbrillance suivant dans Program.cs :

var builder = WebApplication.CreateBuilder(args);

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

Le système de configuration ASP.NET Core lit la chaîne de connexion de base de données « MvcMovieContext ».

Examinez la chaîne de connexion de base de données générée

La génération de modèles a ajouté une chaîne de connexion au fichier appsettings.json :

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

Pour le développement local, le système de configuration ASP.NET Core lit la clé ConnectionString depuis le fichier appsettings.json.

La classe InitialCreate

Examinez le fichier de migration Migrations/{timestamp}_InitialCreate.cs :

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");
        }
    }
}

Dans le code précédent :

  • La méthode InitialCreate.Up crée la table Film et configure Id comme la clé primaire.
  • InitialCreate.Down rétablit les modifications de schéma provoquées par la migration Up.

Injection de dépendances dans le contrôleur

Ouvrez le fichier Controllers/MoviesController.cs et examinez le constructeur :

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Le constructeur utilise une injection de dépendance pour injecter le contexte de base de données (MvcMovieContext) dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

Testez la page Create. Entrez et envoyez des données.

Testez les pages Edit, Details et Delete.

Modèles fortement typés et directive @model

Plus tôt dans ce didacticiel, vous avez vu comment un contrôleur peut passer des données ou des objets à une vue en utilisant le dictionnaire ViewData. Le dictionnaire ViewData est un objet dynamique qui fournit un moyen pratique d’effectuer une liaison tardive pour passer des informations à une vue.

Le modèle MVC fournit la possibilité de passer des objets de modèle fortement typés à une vue. Cette approche fortement typée permet de vérifier votre code au moment de la compilation. Le mécanisme de génération de modèles a passé un modèle fortement typé dans la classe et les vues MoviesController.

Examinez la méthode Details générée dans le fichier Controllers/MoviesController.cs :

// 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);
}

Le paramètre id est généralement passé en tant que données de routage. Par exemple, https://localhost:5001/movies/details/1 définit :

  • Le contrôleur sur le contrôleur movies, le premier segment de l’URL.
  • L’action sur details, le deuxième segment de l’URL.
  • Le id à 1, le dernier segment d’URL.

Le id peut être transmis avec une chaîne de requête, comme dans l’exemple suivant :

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

Le paramètre id est défini comme type Nullable (int?) au cas où la valeur id n’est pas fournie.

Une expression lambda est passée à la méthode FirstOrDefaultAsync pour sélectionner les entités de film qui correspondent aux données de routage ou à la valeur de la chaîne de requête.

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

Si un film est trouvé, une instance du modèle Movie est passée à la vue Details :

return View(movie);

Examinez le contenu du fichier Views/Movies/Details.cshtml :

@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’instruction @model située en haut du fichier de la vue spécifie le type d’objet attendu par la vue. Lorsque le contrôleur de film était créé, l’instruction @model suivante était incluse :

@model MvcMovie.Models.Movie

Cette directive @model autorise l’accès au film que le contrôleur a passé à la vue. L’objet Model est fortement typé. Par exemple, dans la vue Details.cshtml, le code passe chaque champ du film aux Helpers HTML DisplayNameFor et DisplayFor avec l’objet Model fortement typé. Les méthodes et les vues Create et Edit passent aussi un objet du modèle Movie.

Examinez la vue Index.cshtml et la méthode Index dans le contrôleur Movies. Notez comment le code crée un objet List quand il appelle la méthode View. Le code passe cette liste Movies de la méthode d’action Index à la vue :

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

Le code retourne les détails du problème si la propriété Movie du contexte de données est null.

Lors de la création du contrôleur du film, la génération de modèles automatique a inclus l’instruction @model suivante en haut du fichier Index.cshtml :

@model IEnumerable<MvcMovie.Models.Movie>

La directive @model permet d’accéder à la liste des films que le contrôleur a passé à la vue en utilisant un objet Model qui est fortement typé. Par exemple, dans la vue Index.cshtml, le code boucle dans les films avec une instruction foreach sur l’objet Model fortement typé :

@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>

Comme l’objet Model est fortement typé en tant qu’objet IEnumerable<Movie>, chaque élément de la boucle est typé en tant que Movie. Entre autres avantages, le compilateur valide les types utilisés dans le code.

Ressources supplémentaires

Dans ce tutoriel, des classes sont ajoutées pour la gestion des films dans une base de données. Ces classes constituent la partie « Modèle » de l’application MVC.

Ces classes de modèle sont utilisées avec Entity Framework Core (EF Core) pour utiliser une base de données. EF Core est une infrastructure de mappage relationnel d’objets qui simplifie le code d’accès aux données à écrire.

Les classes du modèle créées sont appelées classes POCO, à partir de Plain Old CLR Objects. Les classes POCO n’ont aucune dépendance vis-à-vis de EF Core. Elles définissent uniquement les propriétés des données qui seront stockées dans la base de données.

Dans ce tutoriel, les classes du modèle sont d’abord créées, puis EF Core crée la base de données.

Ajouter une classe de modèle de données

Cliquez avec le bouton droit sur le dossier Modèles >Ajouter>Classe. Nommez le fichier Movie.cs.

Mettez à jour le fichier Models/Movie.cs avec le code suivant :

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 contient un champ Id, qui est nécessaire à la base de données pour la clé primaire.

L’attribut DataType de ReleaseDate spécifie le type de données (Date). Avec cet attribut :

  • L’utilisateur n’est pas obligé d’entrer les informations de temps dans le champ de date.
  • Seule la date est affichée, pas les informations de temps.

Les DataAnnotations sont traitées dans un prochain didacticiel.

La présence du point d’interrogation après string indique que la propriété peut accepter les valeurs Null. Pour plus d’informations, consultez Types référence pouvant accepter la valeur Null.

Ajouter des packages NuGet

Visual Studio installe automatiquement les packages requis.

Générez le projet en tant que vérification des erreurs du compilateur.

Générer automatiquement des pages de film

Utilisez l’outil de génération de modèles automatique pour Create, Read, Update, et Delete des pages du modèle de film.

Cliquez avec le bouton droit sur le dossier Contrôleurs dans l’Explorateur de solutions, puis sélectionnez Ajouter > Nouvel élément généré automatiquement.

affichage de l’étape ci-dessus

Dans la boîte de dialogue Ajouter un nouvel élément de modèle généré automatiquement :

  • Dans le volet gauche, sélectionnez Installé>Communes>MVC.
  • Sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework.
  • Sélectionnez Ajouter.

Boîte de dialogue Ajouter un modèle automatique

Terminez la boîte de dialogue Ajouter un contrôleur MVC avec des vues, à l’aide d’Entity Framework :

  • Dans la liste déroulante Classe du modèle, sélectionnez Film (MvcMovie.Models).
  • Dans la ligne Classe du contexte de données, sélectionnez le signe + (plus).
    • Dans la boîte de dialogue Ajouter un contexte de données, le nom de classe MvcMovie.Data.MvcMovieContext est généré.
    • Cliquez sur Ajouter.
  • Dans la liste déroulante Fournisseur de base de données, sélectionnez SQL Server.
  • Vues et Nom du contrôleur : conservez la valeur par défaut.
  • Cliquez sur Ajouter.

Ajouter un contexte de données – conserver les valeurs par défautSi vous obtenez un message d’erreur, sélectionnez Ajouter une deuxième fois pour réessayer.

La génération de modèles automatique ajoute les packages suivants :

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

La génération automatique crée les éléments suivants :

  • Un contrôleur de films : Controllers/MoviesController.cs
  • Razor afficher les fichiers pour les pages Créer, Supprimer, Détails, Modifier et Indexer : Views/Movies/*.cshtml
  • Une classe de contexte de base de données : Data/MvcMovieContext.cs

La génération de modèles automatique met à jour les éléments suivants :

  • Insère les références de package requises dans le fichier projet MvcMovie.csproj.
  • Inscrit le contexte de base de données dans le fichier Program.cs.
  • Ajoute une chaîne de connexion de base de données au fichier appsettings.json.

La création automatique de ces fichiers et mises à jour est appelée génération de modèles automatique.

Les pages générées automatiquement ne peuvent pas encore être utilisées, car la base de données n’existe pas. L’exécution de l’application et la sélection du lien Application vidéo entraînent un message d’erreur Impossible d’ouvrir la base de données ou Le type de table suivant n’existe pas : Film.

Générez l’application pour vérifier qu’il n’y a pas d’erreurs.

Migration initiale

Utilisez la fonctionnalité EF CoreMigrations pour créer la base de données. La fonctionnalité Migrations est un ensemble d’outils qui vous permettent de créer et de mettre à jour une base de données pour qu’elle corresponde à votre modèle de données.

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package.

Dans la console du Gestionnaire de package, entrez les commandes suivantes :

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Génère un fichier de migration Migrations/{timestamp}_InitialCreate.cs. L’argument InitialCreate est le nom de la migration. Vous pouvez utiliser n’importe quel nom, mais par convention, un nom décrivant la migration est sélectionné. Étant donné qu’il s’agit de la première migration, la classe générée contient du code permettant de créer le schéma de la base de données. Le schéma de base de données est basé sur le modèle spécifié dans la classe MvcMovieContext.

  • Update-Database : Met à jour la base de données vers la dernière migration, qui a été créée par la commande précédente. Cette commande exécute la méthode Up dans le fichier Migrations/{time-stamp}_InitialCreate.cs, qui crée la base de données.

La commande Update-Database génère l’avertissement suivant :

Aucun type n’a été spécifié pour la colonne décimale 'Price' sur le type d’entité 'Movie'. Les valeurs sont tronquées en mode silencieux si elles ne sont pas compatibles avec la précision et l’échelle par défaut. Spécifiez explicitement le type de colonne SQL Server capable d’accueillir toutes les valeurs en utilisant ’HasColumnType()’.

Ignorez l’avertissement précédent, il est résolu dans un tutoriel ultérieur.

Pour plus d’informations sur les outils de la console du gestionnaire de package pour EF Core, consultez EF Core référence sur les outils - Console du gestionnaire de package dans Visual Studio.

Tester l’application

Exécutez l’application et sélectionnez sur le lien Movie App.

Si vous obtenez une exception semblable à ce qui suit, vous avez peut-être manqué la commande Update-Database à l’étape des migrations :

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

Remarque

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que « Anglais » qui utilisent une virgule (« , ») comme décimale et des formats de date autres que le format « Anglais (États-Unis »), l’application doit être localisée. Pour obtenir des instructions sur la localisation, consultez ce problème GitHub.

Examinez la classe de contexte de base de données générée et l’inscription

Avec EF Core, l’accès aux données est effectué à l’aide d’un modèle. Un modèle est constitué de classes d’entité et d’un objet de contexte qui représente une session avec la base de données. L’objet de contexte permet l’interrogation et l’enregistrement des données. Le contexte de base de données est dérivé de Microsoft.EntityFrameworkCore.DbContext et il spécifie les entités à inclure dans le modèle de données.

La génération de modèles crée la classe Data/MvcMovieContext.cs de contexte de base de données :

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; }
    }
}

Le code précédent crée une propriété DbSet<Movie> qui représente les films dans la base de données.

Injection de dépendances

ASP.NET Core comprend l’injection de dépendances (DI). Les services, tels que le contexte de base de données, sont inscrits avec une injection de dépendance dans Program.cs. Ces services sont fournis aux composants qui en ont besoin via des paramètres de constructeur.

Dans le fichier Controllers/MoviesController.cs, le constructeur utilise une injection de dépendance pour injecter le contexte de base de données MvcMovieContext dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

La génération de modèles a généré le code en surbrillance suivant dans Program.cs :

var builder = WebApplication.CreateBuilder(args);

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

Le système de configuration ASP.NET Core lit la chaîne de connexion de base de données « MvcMovieContext ».

Examinez la chaîne de connexion de base de données générée

La génération de modèles a ajouté une chaîne de connexion au fichier appsettings.json :

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

Pour le développement local, le système de configuration ASP.NET Core lit la clé ConnectionString depuis le fichier appsettings.json.

La classe InitialCreate

Examinez le fichier de migration Migrations/{timestamp}_InitialCreate.cs :

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");
        }
    }
}

Dans le code précédent :

  • La méthode InitialCreate.Up crée la table Film et configure Id comme la clé primaire.
  • InitialCreate.Down rétablit les modifications de schéma provoquées par la migration Up.

Injection de dépendances dans le contrôleur

Ouvrez le fichier Controllers/MoviesController.cs et examinez le constructeur :

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Le constructeur utilise une injection de dépendance pour injecter le contexte de base de données (MvcMovieContext) dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

Testez la page Create. Entrez et envoyez des données.

Testez les pages Edit, Details et Delete.

Modèles fortement typés et directive @model

Plus tôt dans ce didacticiel, vous avez vu comment un contrôleur peut passer des données ou des objets à une vue en utilisant le dictionnaire ViewData. Le dictionnaire ViewData est un objet dynamique qui fournit un moyen pratique d’effectuer une liaison tardive pour passer des informations à une vue.

Le modèle MVC fournit la possibilité de passer des objets de modèle fortement typés à une vue. Cette approche fortement typée permet de vérifier votre code au moment de la compilation. Le mécanisme de génération de modèles a passé un modèle fortement typé dans la classe et les vues MoviesController.

Examinez la méthode Details générée dans le fichier Controllers/MoviesController.cs :

// 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);
}

Le paramètre id est généralement passé en tant que données de routage. Par exemple, https://localhost:5001/movies/details/1 définit :

  • Le contrôleur sur le contrôleur movies, le premier segment de l’URL.
  • L’action sur details, le deuxième segment de l’URL.
  • Le id à 1, le dernier segment d’URL.

Le id peut être transmis avec une chaîne de requête, comme dans l’exemple suivant :

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

Le paramètre id est défini comme type Nullable (int?) au cas où la valeur id n’est pas fournie.

Une expression lambda est passée à la méthode FirstOrDefaultAsync pour sélectionner les entités de film qui correspondent aux données de routage ou à la valeur de la chaîne de requête.

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

Si un film est trouvé, une instance du modèle Movie est passée à la vue Details :

return View(movie);

Examinez le contenu du fichier Views/Movies/Details.cshtml :

@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’instruction @model située en haut du fichier de la vue spécifie le type d’objet attendu par la vue. Lorsque le contrôleur de film était créé, l’instruction @model suivante était incluse :

@model MvcMovie.Models.Movie

Cette directive @model autorise l’accès au film que le contrôleur a passé à la vue. L’objet Model est fortement typé. Par exemple, dans la vue Details.cshtml, le code passe chaque champ du film aux Helpers HTML DisplayNameFor et DisplayFor avec l’objet Model fortement typé. Les méthodes et les vues Create et Edit passent aussi un objet du modèle Movie.

Examinez la vue Index.cshtml et la méthode Index dans le contrôleur Movies. Notez comment le code crée un objet List quand il appelle la méthode View. Le code passe cette liste Movies de la méthode d’action Index à la vue :

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

Le code retourne les détails du problème si la propriété Movie du contexte de données est null.

Lors de la création du contrôleur du film, la génération de modèles automatique a inclus l’instruction @model suivante en haut du fichier Index.cshtml :

@model IEnumerable<MvcMovie.Models.Movie>

La directive @model permet d’accéder à la liste des films que le contrôleur a passé à la vue en utilisant un objet Model qui est fortement typé. Par exemple, dans la vue Index.cshtml, le code boucle dans les films avec une instruction foreach sur l’objet Model fortement typé :

@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>

Comme l’objet Model est fortement typé en tant qu’objet IEnumerable<Movie>, chaque élément de la boucle est typé en tant que Movie. Entre autres avantages, le compilateur valide les types utilisés dans le code.

Ressources supplémentaires

Dans ce tutoriel, des classes sont ajoutées pour la gestion des films dans une base de données. Ces classes constituent la partie « Modèle » de l’application MVC.

Ces classes de modèle sont utilisées avec Entity Framework Core (EF Core) pour utiliser une base de données. EF Core est une infrastructure de mappage relationnel d’objets qui simplifie le code d’accès aux données à écrire.

Les classes du modèle créées sont appelées classes POCO, à partir de Plain Old CLR Objects. Les classes POCO n’ont aucune dépendance vis-à-vis de EF Core. Elles définissent uniquement les propriétés des données qui seront stockées dans la base de données.

Dans ce tutoriel, les classes du modèle sont d’abord créées, puis EF Core crée la base de données.

Ajouter une classe de modèle de données

Cliquez avec le bouton droit sur le dossier Modèles >Ajouter>Classe. Nommez le fichier Movie.cs.

Mettez à jour le fichier Models/Movie.cs avec le code suivant :

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 contient un champ Id, qui est nécessaire à la base de données pour la clé primaire.

L’attribut DataType de ReleaseDate spécifie le type de données (Date). Avec cet attribut :

  • L’utilisateur n’est pas obligé d’entrer les informations de temps dans le champ de date.
  • Seule la date est affichée, pas les informations de temps.

Les DataAnnotations sont traitées dans un prochain didacticiel.

La présence du point d’interrogation après string indique que la propriété peut accepter les valeurs Null. Pour plus d’informations, consultez Types référence pouvant accepter la valeur Null.

Ajouter des packages NuGet

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package (PMC).

Menu Console du Gestionnaire de package

Dans la console du gestionnaire de package, exécutez la commande suivante :

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

Les commandes précédentes ajoutent :

  • Fournisseur EF Core SQL Server. Le package du fournisseur installe le package EF Core en tant que dépendance.
  • Utilitaires utilisés par les packages installés automatiquement à l’étape de génération de modèles, plus loin dans le tutoriel.

Générez le projet en tant que vérification des erreurs du compilateur.

Générer automatiquement des pages de film

Utilisez l’outil de génération de modèles automatique pour Create, Read, Update, et Delete des pages du modèle de film.

Cliquez avec le bouton droit sur le dossier Contrôleurs dans l’Explorateur de solutions, puis sélectionnez Ajouter > Nouvel élément généré automatiquement.

affichage de l’étape ci-dessus

Dans la boîte de dialogue Ajouter un modèle automatique, sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework > Ajouter.

Boîte de dialogue Ajouter un modèle automatique

Terminez la boîte de dialogue Ajouter un contrôleur MVC avec des vues, à l’aide d’Entity Framework :

  • Dans la liste déroulante Classe du modèle, sélectionnez Film (MvcMovie.Models).
  • Dans la ligne Classe du contexte de données, sélectionnez le signe + (plus).
    • Dans la boîte de dialogue Ajouter un contexte de données, le nom de classe MvcMovie.Data.MvcMovieContext est généré.
    • Cliquez sur Ajouter.
  • Vues et Nom du contrôleur : conservez la valeur par défaut.
  • Sélectionnez Ajouter.

Ajouter un contexte de données – conserver les valeurs par défaut

Si vous obtenez un message d’erreur, sélectionnez Ajouter une deuxième fois pour réessayer.

La génération de modèles automatique met à jour les éléments suivants :

  • Insère les références de package requises dans le fichier projet MvcMovie.csproj.
  • Inscrit le contexte de base de données dans le fichier Program.cs.
  • Ajoute une chaîne de connexion de base de données au fichier appsettings.json.

La génération automatique crée les éléments suivants :

  • Un contrôleur de films : Controllers/MoviesController.cs
  • Razor afficher les fichiers pour les pages Créer, Supprimer, Détails, Modifier et Indexer : Views/Movies/*.cshtml
  • Une classe de contexte de base de données : Data/MvcMovieContext.cs

La création automatique de ces fichiers et mises à jour est appelée génération de modèles automatique.

Les pages générées automatiquement ne peuvent pas encore être utilisées, car la base de données n’existe pas. L’exécution de l’application et la sélection du lien Application vidéo entraînent un message d’erreur Impossible d’ouvrir la base de données ou Le type de table suivant n’existe pas : Film.

Création de l’application

Générez l'application. Le compilateur génère plusieurs avertissements sur la façon dont les valeurs null sont gérées. Pour plus d’informations, consultez ce problème GitHub et les types de référence pouvant accepter la valeur Null.

Pour éliminer les avertissements des types de référence pouvant accepter la valeur Null, supprimez la ligne suivante du fichier MvcMovie.csproj :

<Nullable>enable</Nullable>

Nous espérons résoudre ce problème dans la prochaine version.

Migration initiale

Utilisez la fonctionnalité EF CoreMigrations pour créer la base de données. La fonctionnalité Migrations est un ensemble d’outils qui vous permettent de créer et de mettre à jour une base de données pour qu’elle corresponde à votre modèle de données.

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package.

Dans la console du Gestionnaire de package, entrez les commandes suivantes :

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Génère un fichier de migration Migrations/{timestamp}_InitialCreate.cs. L’argument InitialCreate est le nom de la migration. Vous pouvez utiliser n’importe quel nom, mais par convention, un nom décrivant la migration est sélectionné. Étant donné qu’il s’agit de la première migration, la classe générée contient du code permettant de créer le schéma de la base de données. Le schéma de base de données est basé sur le modèle spécifié dans la classe MvcMovieContext.

  • Update-Database : Met à jour la base de données vers la dernière migration, qui a été créée par la commande précédente. Cette commande exécute la méthode Up dans le fichier Migrations/{time-stamp}_InitialCreate.cs, qui crée la base de données.

La commande Update-Database génère l’avertissement suivant :

Aucun type n’a été spécifié pour la colonne décimale 'Price' sur le type d’entité 'Movie'. Les valeurs sont tronquées en mode silencieux si elles ne sont pas compatibles avec la précision et l’échelle par défaut. Spécifiez explicitement le type de colonne SQL Server capable d’accueillir toutes les valeurs en utilisant ’HasColumnType()’.

Ignorez l’avertissement précédent, il est résolu dans un tutoriel ultérieur.

Pour plus d’informations sur les outils de la console du gestionnaire de package pour EF Core, consultez EF Core référence sur les outils - Console du gestionnaire de package dans Visual Studio.

Test de l'application

Exécutez l’application et sélectionnez sur le lien Movie App.

Si vous obtenez une exception similaire à ce qui suit, vous avez peut-être manqué l’étape de migration :

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

Remarque

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que « Anglais » qui utilisent une virgule (« , ») comme décimale et des formats de date autres que le format « Anglais (États-Unis »), l’application doit être localisée. Pour obtenir des instructions sur la localisation, consultez ce problème GitHub.

Examinez la classe de contexte de base de données générée et l’inscription

Avec EF Core, l’accès aux données est effectué à l’aide d’un modèle. Un modèle est constitué de classes d’entité et d’un objet de contexte qui représente une session avec la base de données. L’objet de contexte permet l’interrogation et l’enregistrement des données. Le contexte de base de données est dérivé de Microsoft.EntityFrameworkCore.DbContext et il spécifie les entités à inclure dans le modèle de données.

La génération de modèles crée la classe Data/MvcMovieContext.cs de contexte de base de données :

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; }
    }
}

Le code précédent crée une propriété DbSet<Movie> qui représente les films dans la base de données.

Injection de dépendances

ASP.NET Core comprend l’injection de dépendances (DI). Les services, tels que le contexte de base de données, sont inscrits avec une injection de dépendance dans Program.cs. Ces services sont fournis aux composants qui en ont besoin via des paramètres de constructeur.

Dans le fichier Controllers/MoviesController.cs, le constructeur utilise une injection de dépendance pour injecter le contexte de base de données MvcMovieContext dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

La génération de modèles a généré le code en surbrillance suivant dans Program.cs :

var builder = WebApplication.CreateBuilder(args);

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

Le système de configuration ASP.NET Core lit la chaîne de connexion de base de données « MvcMovieContext ».

Examinez la chaîne de connexion de base de données générée

La génération de modèles a ajouté une chaîne de connexion au fichier appsettings.json :

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

Pour le développement local, le système de configuration ASP.NET Core lit la clé ConnectionString depuis le fichier appsettings.json.

La classe InitialCreate

Examinez le fichier de migration Migrations/{timestamp}_InitialCreate.cs :

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");
        }
    }
}

Dans le code précédent :

  • La méthode InitialCreate.Up crée la table Film et configure Id comme la clé primaire.
  • InitialCreate.Down rétablit les modifications de schéma provoquées par la migration Up.

Injection de dépendances dans le contrôleur

Ouvrez le fichier Controllers/MoviesController.cs et examinez le constructeur :

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Le constructeur utilise une injection de dépendance pour injecter le contexte de base de données (MvcMovieContext) dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

Testez la page Create. Entrez et envoyez des données.

Testez les pages Edit, Details et Delete.

Modèles fortement typés et directive @model

Plus tôt dans ce didacticiel, vous avez vu comment un contrôleur peut passer des données ou des objets à une vue en utilisant le dictionnaire ViewData. Le dictionnaire ViewData est un objet dynamique qui fournit un moyen pratique d’effectuer une liaison tardive pour passer des informations à une vue.

Le modèle MVC fournit la possibilité de passer des objets de modèle fortement typés à une vue. Cette approche fortement typée permet de vérifier votre code au moment de la compilation. Le mécanisme de génération de modèles a passé un modèle fortement typé dans la classe et les vues MoviesController.

Examinez la méthode Details générée dans le fichier Controllers/MoviesController.cs :

// 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);
}

Le paramètre id est généralement passé en tant que données de routage. Par exemple, https://localhost:5001/movies/details/1 définit :

  • Le contrôleur sur le contrôleur movies, le premier segment de l’URL.
  • L’action sur details, le deuxième segment de l’URL.
  • Le id à 1, le dernier segment d’URL.

Le id peut être transmis avec une chaîne de requête, comme dans l’exemple suivant :

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

Le paramètre id est défini comme type Nullable (int?) au cas où la valeur id n’est pas fournie.

Une expression lambda est passée à la méthode FirstOrDefaultAsync pour sélectionner les entités de film qui correspondent aux données de routage ou à la valeur de la chaîne de requête.

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

Si un film est trouvé, une instance du modèle Movie est passée à la vue Details :

return View(movie);

Examinez le contenu du fichier Views/Movies/Details.cshtml :

@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’instruction @model située en haut du fichier de la vue spécifie le type d’objet attendu par la vue. Lorsque le contrôleur de film était créé, l’instruction @model suivante était incluse :

@model MvcMovie.Models.Movie

Cette directive @model autorise l’accès au film que le contrôleur a passé à la vue. L’objet Model est fortement typé. Par exemple, dans la vue Details.cshtml, le code passe chaque champ du film aux Helpers HTML DisplayNameFor et DisplayFor avec l’objet Model fortement typé. Les méthodes et les vues Create et Edit passent aussi un objet du modèle Movie.

Examinez la vue Index.cshtml et la méthode Index dans le contrôleur Movies. Notez comment le code crée un objet List quand il appelle la méthode View. Le code passe cette liste Movies de la méthode d’action Index à la vue :

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

Lors de la création du contrôleur du film, la génération de modèles automatique a inclus l’instruction @model suivante en haut du fichier Index.cshtml :

@model IEnumerable<MvcMovie.Models.Movie>

La directive @model permet d’accéder à la liste des films que le contrôleur a passé à la vue en utilisant un objet Model qui est fortement typé. Par exemple, dans la vue Index.cshtml, le code boucle dans les films avec une instruction foreach sur l’objet Model fortement typé :

@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>

Comme l’objet Model est fortement typé en tant qu’objet IEnumerable<Movie>, chaque élément de la boucle est typé en tant que Movie. Entre autres avantages, le compilateur valide les types utilisés dans le code.

Ressources supplémentaires

Dans ce tutoriel, des classes sont ajoutées pour la gestion des films dans une base de données. Ces classes constituent la partie « Modèle » de l’application MVC.

Ces classes de modèle sont utilisées avec Entity Framework Core (EF Core) pour utiliser une base de données. EF Core est une infrastructure de mappage relationnel d’objets qui simplifie le code d’accès aux données à écrire.

Les classes du modèle créées sont appelées classes POCO, à partir de Plain Old CLR Objects. Les classes POCO n’ont aucune dépendance vis-à-vis de EF Core. Elles définissent uniquement les propriétés des données qui seront stockées dans la base de données.

Dans ce tutoriel, les classes du modèle sont d’abord créées, puis EF Core crée la base de données.

Ajouter une classe de modèle de données

Cliquez avec le bouton droit sur le dossier Modèles >Ajouter>Classe. Nommez le fichier Movie.cs.

Mettez à jour le fichier Models/Movie.cs avec le code suivant :

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 contient un champ Id, qui est nécessaire à la base de données pour la clé primaire.

L’attribut DataType de ReleaseDate spécifie le type de données (Date). Avec cet attribut :

  • L’utilisateur n’est pas obligé d’entrer les informations de temps dans le champ de date.
  • Seule la date est affichée, pas les informations de temps.

Les DataAnnotations sont traitées dans un prochain didacticiel.

Ajouter des packages NuGet

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package (PMC).

Menu Console du Gestionnaire de package

Dans la console du gestionnaire de package, exécutez la commande suivante :

Install-Package Microsoft.EntityFrameworkCore.Design

Les commandes précédentes ajoutent :

  • Fournisseur EF Core SQL Server. Le package du fournisseur installe le package EF Core en tant que dépendance.
  • Utilitaires utilisés par les packages installés automatiquement à l’étape de génération de modèles, plus loin dans le tutoriel.

Générez le projet en tant que vérification des erreurs du compilateur.

Générer automatiquement des pages de film

Utilisez l’outil de génération de modèles automatique pour Create, Read, Update, et Delete des pages du modèle de film.

Cliquez avec le bouton droit sur le dossier Contrôleurs dans l’Explorateur de solutions, puis sélectionnez Ajouter > Nouvel élément généré automatiquement.

affichage de l’étape ci-dessus

Dans la boîte de dialogue Ajouter un modèle automatique, sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework > Ajouter.

Boîte de dialogue Ajouter un modèle automatique

Terminez la boîte de dialogue Ajouter un contrôleur MVC avec des vues, à l’aide d’Entity Framework :

  • Dans la liste déroulante Classe du modèle, sélectionnez Film (MvcMovie.Models).
  • Dans la ligne Classe du contexte de données, sélectionnez le signe + (plus).
    • Dans la boîte de dialogue Ajouter un contexte de données, le nom de classe MvcMovie.Data.MvcMovieContext est généré.
    • Cliquez sur Ajouter.
  • Vues et Nom du contrôleur : conservez la valeur par défaut.
  • Sélectionnez Ajouter.

Ajouter un contexte de données – conserver les valeurs par défaut

La génération de modèles automatique met à jour les éléments suivants :

  • Insère les références de package requises dans le fichier projet MvcMovie.csproj.
  • Inscrit le contexte de base de données dans Startup.ConfigureServices du fichier Startup.cs.
  • Ajoute une chaîne de connexion de base de données au fichier appsettings.json.

La génération automatique crée les éléments suivants :

  • Un contrôleur de films : Controllers/MoviesController.cs
  • Razor afficher les fichiers pour les pages Créer, Supprimer, Détails, Modifier et Indexer : Views/Movies/*.cshtml
  • Une classe de contexte de base de données : Data/MvcMovieContext.cs

La création automatique de ces fichiers et mises à jour de fichiers est appelée génération de modèles automatique.

Les pages générées automatiquement ne peuvent pas encore être utilisées, car la base de données n’existe pas. L’exécution de l’application et la sélection du lien Application vidéo entraînent un message d’erreur Impossible d’ouvrir la base de données ou Le type de table suivant n’existe pas : Film.

Migration initiale

Utilisez la fonctionnalité EF CoreMigrations pour créer la base de données. Les migrations sont un ensemble d’outils qui créent et mettent à jour une base de données pour correspondre au modèle de données.

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package.

Dans la console du Gestionnaire de package, entrez les commandes suivantes :

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Génère un fichier de migration Migrations/{timestamp}_InitialCreate.cs. L’argument InitialCreate est le nom de la migration. Vous pouvez utiliser n’importe quel nom, mais par convention, un nom décrivant la migration est sélectionné. Étant donné qu’il s’agit de la première migration, la classe générée contient du code permettant de créer le schéma de la base de données. Le schéma de base de données est basé sur le modèle spécifié dans la classe MvcMovieContext.

  • Update-Database : Met à jour la base de données vers la dernière migration, qui a été créée par la commande précédente. Cette commande exécute la méthode Up dans le fichier Migrations/{time-stamp}_InitialCreate.cs, qui crée la base de données.

La commande Update-Database génère l’avertissement suivant :

Aucun type n’a été spécifié pour la colonne décimale 'Price' sur le type d’entité 'Movie'. Les valeurs sont tronquées en mode silencieux si elles ne sont pas compatibles avec la précision et l’échelle par défaut. Spécifiez explicitement le type de colonne SQL Server capable d’accueillir toutes les valeurs en utilisant ’HasColumnType()’.

Ignorez l’avertissement précédent, il est résolu dans un tutoriel ultérieur.

Pour plus d’informations sur les outils de la console du gestionnaire de package pour EF Core, consultez EF Core référence sur les outils - Console du gestionnaire de package dans Visual Studio.

Test de l'application

Exécutez l’application et sélectionnez sur le lien Movie App.

Si vous obtenez une exception similaire à ce qui suit, vous avez peut-être manqué l’étape de migration :

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

Remarque

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que « Anglais » qui utilisent une virgule (« , ») comme décimale et des formats de date autres que le format « Anglais (États-Unis »), l’application doit être localisée. Pour obtenir des instructions sur la localisation, consultez ce problème GitHub.

Examinez la classe de contexte de base de données générée et l’inscription

Avec EF Core, l’accès aux données est effectué à l’aide d’un modèle. Un modèle est constitué de classes d’entité et d’un objet de contexte qui représente une session avec la base de données. L’objet de contexte permet l’interrogation et l’enregistrement des données. Le contexte de base de données est dérivé de Microsoft.EntityFrameworkCore.DbContext et il spécifie les entités à inclure dans le modèle de données.

La génération de modèles crée la classe Data/MvcMovieContext.cs de contexte de base de données :

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; }
    }
}

Le code précédent crée une propriété DbSet<Movie> qui représente les films dans la base de données.

ASP.NET Core comprend l’injection de dépendances (DI). Les services, tels que le contexte de base de données, doivent être inscrits avec l’injection de dépendances dans Startup. Les composants qui nécessitent ces services sont fournis via des paramètres de constructeur.

Dans le fichier Controllers/MoviesController.cs, le constructeur utilise une injection de dépendance pour injecter le contexte de base de données MvcMovieContext dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

La génération de modèles a généré le code en surbrillance suivant dans Startup.ConfigureServices :

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

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

Le système de configuration ASP.NET Core lit la chaîne de connexion de base de données « MvcMovieContext ».

Examinez la chaîne de connexion de base de données générée

La génération de modèles a ajouté une chaîne de connexion au fichier appsettings.json :

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

Pour le développement local, le système de configuration ASP.NET Core lit la clé ConnectionString depuis le fichier appsettings.json.

La classe InitialCreate

Examinez le fichier de migration Migrations/{timestamp}_InitialCreate.cs :

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");
    }
}

Dans le code précédent :

  • La méthode InitialCreate.Up crée la table Film et configure Id comme la clé primaire.
  • InitialCreate.Down rétablit les modifications de schéma provoquées par la migration Up.

Injection de dépendances dans le contrôleur

Ouvrez le fichier Controllers/MoviesController.cs et examinez le constructeur :

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Le constructeur utilise une injection de dépendance pour injecter le contexte de base de données (MvcMovieContext) dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

Testez la page Create. Entrez et envoyez des données.

Testez les pages Edit, Details et Delete.

Modèles fortement typés et directive @model

Plus tôt dans ce didacticiel, vous avez vu comment un contrôleur peut passer des données ou des objets à une vue en utilisant le dictionnaire ViewData. Le dictionnaire ViewData est un objet dynamique qui fournit un moyen pratique d’effectuer une liaison tardive pour passer des informations à une vue.

Le modèle MVC fournit la possibilité de passer des objets de modèle fortement typés à une vue. Cette approche fortement typée permet de vérifier votre code au moment de la compilation. Le mécanisme de génération de modèles a passé un modèle fortement typé dans la classe et les vues MoviesController.

Examinez la méthode Details générée dans le fichier Controllers/MoviesController.cs :

// 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);
}

Le paramètre id est généralement passé en tant que données de routage. Par exemple, https://localhost:5001/movies/details/1 définit :

  • Le contrôleur sur le contrôleur movies, le premier segment de l’URL.
  • L’action sur details, le deuxième segment de l’URL.
  • Le id à 1, le dernier segment d’URL.

Le id peut être transmis avec une chaîne de requête, comme dans l’exemple suivant :

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

Le paramètre id est défini comme type Nullable (int?) au cas où la valeur id n’est pas fournie.

Une expression lambda est passée à la méthode FirstOrDefaultAsync pour sélectionner les entités de film qui correspondent aux données de routage ou à la valeur de la chaîne de requête.

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

Si un film est trouvé, une instance du modèle Movie est passée à la vue Details :

return View(movie);

Examinez le contenu du fichier Views/Movies/Details.cshtml :

@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’instruction @model située en haut du fichier de la vue spécifie le type d’objet attendu par la vue. Lorsque le contrôleur de film était créé, l’instruction @model suivante était incluse :

@model MvcMovie.Models.Movie

Cette directive @model autorise l’accès au film que le contrôleur a passé à la vue. L’objet Model est fortement typé. Par exemple, dans la vue Details.cshtml, le code passe chaque champ du film aux Helpers HTML DisplayNameFor et DisplayFor avec l’objet Model fortement typé. Les méthodes et les vues Create et Edit passent aussi un objet du modèle Movie.

Examinez la vue Index.cshtml et la méthode Index dans le contrôleur Movies. Notez comment le code crée un objet List quand il appelle la méthode View. Le code passe cette liste Movies de la méthode d’action Index à la vue :

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

Lors de la création du contrôleur du film, la génération de modèles automatique a inclus l’instruction @model suivante en haut du fichier Index.cshtml :

@model IEnumerable<MvcMovie.Models.Movie>

La directive @model permet d’accéder à la liste des films que le contrôleur a passé à la vue en utilisant un objet Model qui est fortement typé. Par exemple, dans la vue Index.cshtml, le code boucle dans les films avec une instruction foreach sur l’objet Model fortement typé :

@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>

Comme l’objet Model est fortement typé en tant qu’objet IEnumerable<Movie>, chaque élément de la boucle est typé en tant que Movie. Entre autres avantages, le compilateur valide les types utilisés dans le code.

Journalisation SQL d’Entity Framework Core

La configuration de la journalisation est généralement fournie par la section Logging des fichiers appsettings.{Environment}.json. Pour journaliser les instructions SQL, ajoutez "Microsoft.EntityFrameworkCore.Database.Command": "Information" au fichier appsettings.Development.json :

{
  "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": "*"
}

Avec le JSON précédent, les instructions SQL s’affichent dans la ligne de commande et dans la fenêtre de sortie de Visual Studio.

Pour plus d’informations, consultez Journalisation dans .NET Core et ASP.NET Core et ce problème GitHub.

Ressources supplémentaires

Dans ce tutoriel, des classes sont ajoutées pour la gestion des films dans une base de données. Ces classes constituent la partie « Modèle » de l’application MVC.

Ces classes de modèle sont utilisées avec Entity Framework Core (EF Core) pour utiliser une base de données. EF Core est une infrastructure de mappage relationnel d’objets qui simplifie le code d’accès aux données à écrire.

Les classes du modèle créées sont appelées classes POCO, à partir de Plain Old CLR Objects. Les classes POCO n’ont aucune dépendance vis-à-vis de EF Core. Elles définissent uniquement les propriétés des données qui seront stockées dans la base de données.

Dans ce tutoriel, les classes du modèle sont d’abord créées, puis EF Core crée la base de données.

Ajouter une classe de modèle de données

Cliquez avec le bouton droit sur le dossier Modèles >Ajouter>Classe. Nommez le fichier Movie.cs.

Mettez à jour le fichier Movie.cs avec le code suivant :

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 contient un champ Id, qui est nécessaire à la base de données pour la clé primaire.

L’attribut DataType de ReleaseDate spécifie le type de données (Date). Avec cet attribut :

  • L’utilisateur n’est pas obligé d’entrer les informations de temps dans le champ de date.
  • Seule la date est affichée, pas les informations de temps.

Les DataAnnotations sont traitées dans un prochain didacticiel.

Ajouter des packages NuGet

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package (PMC).

Menu Console du Gestionnaire de package

Dans la console du gestionnaire de package, exécutez la commande suivante :

Install-Package Microsoft.EntityFrameworkCore.SqlServer

La commande précédente ajoute le fournisseur EF Core SQL Server. Le package du fournisseur installe le package EF Core en tant que dépendance. Plus loin dans ce tutoriel, d’autres packages sont installés automatiquement lors de l’étape de génération de modèles automatique.

Créer une classe de contexte de base de données

Une classe de contexte de base de données est nécessaire pour coordonner une fonctionnalité EF Core (Créer, Lire, Mettre à jour, Supprimer) pour le modèle Movie. Le contexte de base de données est dérivé de Microsoft.EntityFrameworkCore.DbContext et il spécifie les entités à inclure dans le modèle de données.

Créez un dossier nommé Data.

Ajoutez un fichier Data/MvcMovieContext.cs avec le code suivant :

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; }
    }
}

Le code précédent crée une propriété DbSet<Movie> pour le jeu d’entités. Dans la terminologie Entity Framework, un jeu d’entités correspond généralement à une table de base de données. Une entité correspond à une ligne dans la table.

Inscrire le contexte de base de données

ASP.NET Core comprend l’injection de dépendances (DI). Les services (tels que le contexte de base de données EF Core) doivent être inscrits avec l’injection de dépendances au démarrage de l’application. Ces services sont affectés aux composants qui les nécessitent (par exemple les Pages Razor) par le biais de paramètres de constructeur. Le code du constructeur qui obtient une instance de contexte de base de données est indiqué plus loin dans le tutoriel. Dans cette section, vous allez inscrire le contexte de base de données auprès du conteneur d’injection de dépendances.

En tête du Startup.cs, ajoutez les instructions using suivantes :

using MvcMovie.Data;
using Microsoft.EntityFrameworkCore;

Ajoutez le code en surbrillance suivant dans Startup.ConfigureServices :

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

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

Le nom de la chaîne de connexion est transmis au contexte en appelant une méthode sur un objet DbContextOptions. Pour le développement local, le système de configuration ASP.NET Core lit la chaîne de connexion à partir du fichier appsettings.json.

Examiner la chaîne de connexion de base de données

Ajoutez une chaîne de connexion au fichier appsettings.json :

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

Générez le projet en tant que vérification des erreurs du compilateur.

Générer automatiquement des pages de film

Utilisez l’outil de génération de modèles automatique pour créer, lire, mettre à jour et supprimer des pages du modèle de film.

Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le dossier Contrôleurs, puis choisissez >Ajouter > Nouvel élément généré automatiquement.

affichage de l’étape ci-dessus

Dans la boîte de dialogue Ajouter un modèle automatique, sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework > Ajouter.

Boîte de dialogue Ajouter un modèle automatique

Renseignez la boîte de dialogue Ajouter un contrôleur :

  • Classe de modèle : Movie (MvcMovie.Models)
  • Classe de contexte de données : MvcMovieContext (MvcMovie.Data)

Ajouter un contexte de données

  • Affichages : conservez la valeur par défaut de chaque option activée.
  • Nom du contrôleur : conservez la valeur par défaut MoviesController.
  • Sélectionnez Ajouter

Visual Studio crée :

  • Un contrôleur de films (Controllers/MoviesController.cs)
  • Des fichiers de vues Razor pour les pages Créer, Supprimer, Détails, Modifier et Index (Views/Movies/.cshtml)

La création automatique de ces fichiers est appelée génération de modèles automatique.

Vous ne pouvez pas encore utiliser les pages générées automatiquement, car la base de données n’existe pas. Si vous exécutez l’application et cliquez sur le lien de l’application Movie, vous obtenez un message d’erreur Impossible d’ouvrir la base de données ou La table suivante n’existe pas.

Migration initiale

Utilisez la fonctionnalité EF CoreMigrations pour créer la base de données. La fonctionnalité Migrations est un ensemble d’outils qui vous permettent de créer et de mettre à jour une base de données pour qu’elle corresponde à votre modèle de données.

Dans le menu Outils, sélectionnez Gestionnaire de package NuGet>Console du gestionnaire de package (PMC).

Dans la console du Gestionnaire de package, entrez les commandes suivantes :

Add-Migration InitialCreate
Update-Database
  • Add-Migration InitialCreate: Génère un Migrations/{timestamp}_InitialCreate.cs fichier de migration. L’argument InitialCreate est le nom de la migration. Vous pouvez utiliser n’importe quel nom, mais par convention, un nom décrivant la migration est sélectionné. Étant donné qu’il s’agit de la première migration, la classe générée contient du code permettant de créer le schéma de la base de données. Le schéma de base de données est basé sur le modèle spécifié dans la classe MvcMovieContext.

  • Update-Database : Met à jour la base de données vers la dernière migration, qui a été créée par la commande précédente. Cette commande exécute la méthode Up dans le fichier Migrations/{time-stamp}_InitialCreate.cs, qui crée la base de données.

    La commande « database update » génère l’avertissement suivant :

    Aucun type n’a été spécifié pour la colonne décimale 'Price' sur le type d’entité 'Movie'. Les valeurs sont tronquées en mode silencieux si elles ne sont pas compatibles avec la précision et l’échelle par défaut. Spécifiez explicitement le type de colonne SQL Server capable d’accueillir toutes les valeurs en utilisant ’HasColumnType()’.

    Vous pouvez ignorer cet avertissement, il sera corrigé dans un prochain tutoriel.

Pour plus d’informations sur les outils de la console du gestionnaire de package pour EF Core, consultez EF Core référence sur les outils - Console du gestionnaire de package dans Visual Studio.

La classe InitialCreate

Examinez le fichier de migration Migrations/{timestamp}_InitialCreate.cs :

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");
    }
}

La méthode Up crée la table Movie et configure Id comme la clé primaire. La méthode Down rétablit les modifications de schéma provoquées par la migration Up.

Test de l'application

  • Exécutez l’application et cliquez sur le lien Movie App.

    Si vous obtenez une exception similaire à celle-ci :

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

Il est probable que vous n’ayez pas effectué l’étape de migration.

  • Testez la page Create. Entrez et envoyez des données.

    Remarque

    Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que « Anglais » qui utilisent une virgule (« , ») comme décimale et des formats de date autres que le format « Anglais (États-Unis »), l’application doit être localisée. Pour obtenir des instructions sur la localisation, consultez ce problème GitHub.

  • Testez les pages Edit, Details et Delete.

Injection de dépendances dans le contrôleur

Ouvrez le fichier Controllers/MoviesController.cs et examinez le constructeur :

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Le constructeur utilise une injection de dépendance pour injecter le contexte de base de données (MvcMovieContext) dans le contrôleur. Le contexte de base de données est utilisé dans chacune des méthodes la CRUD du contrôleur.

Modèles fortement typés et mot clé @model

Plus tôt dans ce didacticiel, vous avez vu comment un contrôleur peut passer des données ou des objets à une vue en utilisant le dictionnaire ViewData. Le dictionnaire ViewData est un objet dynamique qui fournit un moyen pratique d’effectuer une liaison tardive pour passer des informations à une vue.

Le modèle MVC fournit également la possibilité de passer des objets de modèle fortement typés à une vue. Cette approche fortement typée permet de vérifier votre code au moment de la compilation. Le mécanisme de génération de modèles automatique a utilisé cette approche (c’est-à-dire passer un modèle fortement typé) avec la classe MoviesController et des vues.

Examinez la méthode Details générée dans le fichier Controllers/MoviesController.cs :

// 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);
}

Le paramètre id est généralement passé en tant que données de routage. Par exemple, https://localhost:5001/movies/details/1 définit :

  • Le contrôleur sur le contrôleur movies (le premier segment de l’URL).
  • L’action sur details (le deuxième segment de l’URL).
  • L’ID sur 1 (le dernier segment de l’URL).

Vous pouvez aussi passer id avec une requête de chaîne, comme suit :

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

Le paramètre id est défini comme type nullable (int?) au cas où la valeur d’ID n’est pas fournie.

Une expression lambda est passée à FirstOrDefaultAsync pour sélectionner les entités de film qui correspondent aux données de routage ou à la valeur de la chaîne de requête.

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

Si un film est trouvé, une instance du modèle Movie est passée à la vue Details :

return View(movie);

Examinez le contenu du fichier Views/Movies/Details.cshtml :

@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’instruction @model située en haut du fichier de la vue spécifie le type d’objet attendu par la vue. Lorsque le contrôleur de film était créé, l’instruction @model suivante était incluse :

@model MvcMovie.Models.Movie

Cette directive @model autorise l’accès au film que le contrôleur a passé à la vue. L’objet Model est fortement typé. Par exemple, dans la vue Details.cshtml, le code passe chaque champ du film aux Helpers HTML DisplayNameFor et DisplayFor avec l’objet Model fortement typé. Les méthodes et les vues Create et Edit passent aussi un objet du modèle Movie.

Examinez la vue Index.cshtml et la méthode Index dans le contrôleur Movies. Notez comment le code crée un objet List quand il appelle la méthode View. Le code passe cette liste Movies de la méthode d’action Index à la vue :

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

Lors de la création du contrôleur du film, la génération de modèles automatique a inclus l’instruction @model suivante en haut du fichier Index.cshtml :

@model IEnumerable<MvcMovie.Models.Movie>

La directive @model vous permet d’accéder à la liste des films que le contrôleur a passé à la vue en utilisant un objet Model qui est fortement typé. Par exemple, dans la vue Index.cshtml, le code boucle dans les films avec une instruction foreach sur l’objet Model fortement typé :

@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>

Comme l’objet Model est fortement typé (en tant qu’objet IEnumerable<Movie>), chaque élément de la boucle est typé en tant que Movie. Entre autres avantages, cela signifie que votre code est vérifié au moment de la compilation :

Ressources supplémentaires