Tutoriel : bien démarrer avec EF Core dans une application web ASP.NET MVC

Par Tom Dykstra et Rick Anderson

Ce didacticiel décrit ASP.NET Core MVC et Entity Framework Core avec des contrôleurs et des vues. Razor Pages est un autre modèle de programmation. Pour le nouveau développement, nous recommandons Razor Pages plutôt que MVC avec des contrôleurs et des vues. Consultez la version Razor Pages de ce tutoriel. Chaque tutoriel couvre des sujets que l’autre ne couvre pas :

Ce tutoriel MVC présente certains éléments que le tutoriel Razor Pages ne présente pas :

  • Implémenter l’héritage dans le modèle de données
  • Exécuter des requêtes SQL brutes
  • Utiliser du code dynamique LINQ pour simplifier le code

Voici certains éléments que le tutoriel Razor Pages présente, contrairement à celui-ci :

  • Utiliser la méthode Select pour charger les données associées
  • Bonnes pratiques pour EF.

L’exemple d’application web Contoso University montre comment créer une application web ASP.NET Core MVC à l’aide d’Entity Framework (EF) Core et Visual Studio.

L’exemple d’application est un site web pour une université Contoso fictive. Il comprend des fonctionnalités telles que l’admission des étudiants, la création des cours et les affectations des formateurs. Ce tutoriel est le premier d’une série qui explique comment générer l’exemple d’application Contoso University.

Prérequis

Ce tutoriel n’a pas été mis à jour pour ASP.NET Core 6 ou version ultérieure. Les instructions de ce tutoriel ne fonctionneront pas correctement si vous créez un projet qui cible ASP.NET Core 6 ou une version ultérieure. Par exemple, les modèles web ASP.NET Core 6 et versions ultérieures utilisent le modèle d’hébergement minimal, qui rassemble Startup.cs et Program.cs en un seul fichier Program.cs.

Une autre différence introduite dans .NET 6 est la fonctionnalité NRT (types de référence null). Les modèles de projet activent cette fonctionnalité par défaut. Des problèmes peuvent se produire. EF considère alors qu’une propriété est requise dans .NET 6, qui peut accepter la valeur Null dans .NET 5. Par exemple, la page Créer un étudiant échoue en mode silencieux, sauf si la propriété Enrollments est rendue comme pouvant accepter la valeur Null ou si la balise d’assistance asp-validation-summary passe de ModelOnly à All.

Nous vous recommandons d’installer et d’utiliser le Kit de développement logiciel (SDK) .NET 5 dans le cadre de ce tutoriel. Tant que ce tutoriel n’est pas mis à jour, consultez Razor Pages avec Entity Framework Core dans ASP.NET Core - Tutoriel 1 sur 8 sur l’utilisation d’Entity Framework avec ASP.NET Core 6 ou version ultérieure.

Moteurs de base de données

Les instructions Visual Studio utilisent la Base de données locale SQL Server, version de SQL Server Express qui s’exécute uniquement sur Windows.

Détecter et résoudre des problèmes

Si vous rencontrez un problème que vous ne pouvez pas résoudre, vous pouvez généralement trouver la solution en comparant votre code au projet terminé. Pour obtenir la liste des erreurs courantes et comment les résoudre, consultez la section Dépannage du dernier didacticiel de la série. Si vous n’y trouvez pas ce dont vous avez besoin, vous pouvez publier une question sur StackOverflow.com pour ASP.NET Core ou EF Core.

Conseil

Il s’agit d’une série de 10 didacticiels, dont chacun s’appuie sur les opérations réalisées dans les précédents. Pensez à enregistrer une copie du projet à la fin de chaque didacticiel réussi. Ainsi, si vous rencontrez des problèmes, vous pouvez recommencer à la fin du didacticiel précédent au lieu de revenir au début de la série entière.

Application web Contoso University

L’application générée dans ces didacticiels est le site web de base d’une université.

Les utilisateurs peuvent afficher et mettre à jour les informations relatives aux étudiants, aux cours et aux formateurs. Voici quelques écrans dans l’application :

Page d’index des étudiants

Page de modification des étudiants

Créer une application web

  1. Démarrez Visual Studio et sélectionnez Créer un projet.
  2. Dans la boîte de dialogue Créer un nouveau projet, sélectionnez Application web ASP.NET Core>Next.
  3. Dans la boîte de dialogue Configurer votre nouveau projet, entrez ContosoUniversity pour Nom du projet. Il est important d’utiliser ce nom exact, en respectant l’utilisation des majuscules, de sorte que chaque namespace corresponde au moment où le code est copié.
  4. Cliquez sur Créer.
  5. Dans la boîte de dialogue Créer une nouvelle application web ASP.NET Core, sélectionnez :
    1. .NET Core et ASP.NET Core 5.0 dans les listes déroulantes.
    2. Application web ASP.NET Core (modèle-vue-contrôleur).
    3. CréerBoîte de dialogue Nouveau projet ASP.NET Core

Configurer le style du site

Quelques changements basiques permettent de définir le menu, la mise en page et la page home du site.

Ouvrez Views/Shared/_Layout.cshtml et apportez les changements suivants :

  • Remplacez chaque occurrence de ContosoUniversity par Contoso University. Il y a trois occurrences.
  • Ajoutez des entrées de menu pour À propos, Étudiants, Cours, Formateurs et Departments, et supprimez l’entrée de menu Privacy.

Les modifications précédentes sont mises en évidence dans le code suivant :

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

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Dans Views/Home/Index.cshtml, remplacez le contenu du fichier par la balise suivante :

@{
    ViewData["Title"] = "Home Page";
}

<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core MVC web application.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/5cu-final">See project source code &raquo;</a></p>
    </div>
</div>

Appuyez sur Ctrl+F5 pour exécuter le projet ou choisissez Déboguer > Exécuter sans débogage dans le menu. La page home s’affiche avec des onglets pour les pages créées dans ce tutoriel.

Page home de Contoso University

PackagesEF Core NuGet

Ce didacticiel utilise SQL Server et le package de fournisseur est Microsoft.EntityFrameworkCore.SqlServer.

Le package EF SQL Server et ses dépendances,Microsoft.EntityFrameworkCore et Microsoft.EntityFrameworkCore.Relational, fournissent la prise en charge du runtime pour EF.

Ajoutez le package NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore. Dans la console du Gestionnaire de package, saisissez les commandes suivantes pour installer les packages NuGet :

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer

Le package NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore fournit l’intergiciel ASP.NET Core pour les pages d’erreur EF Core. Cet intergiciel permet de détecter et de diagnostiquer les erreurs liées aux migrations EF Core.

Pour obtenir des informations sur les autres fournisseurs de bases de données qui sont disponibles pour EF Core, consultez Fournisseurs de bases de données.

Créer le modèle de données

Les classes d’entité suivantes sont créées pour cette application :

Diagramme du modèle de données Course-Enrollment-Student

Les entités précédentes ont les relations suivantes :

  • Une relation un-à-plusieurs entre les entités Student et Enrollment. Un étudiant peut être inscrit à autant de cours qu’il le souhaite.
  • Une relation un-à-plusieurs entre les entités Course et Enrollment. Un cours peut avoir une quantité illimitée d’élèves inscrits.

Dans les sections suivantes, une classe est créée pour chacune de ces entités.

L’entité Student

Diagramme de l’entité Student

Dans le dossier Modèles, créez la classe Student avec le code suivant :

using System;
using System.Collections.Generic;

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

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

La propriété ID devient la colonne de clé primaire (PK) de la table de base de données qui correspond à cette classe. Par défaut, EF interprète une propriété nommée ID ou classnameID comme clé primaire. Par exemple, la PK peut être nommée StudentID plutôt que ID.

La propriété Enrollments est une propriété de navigation. Les propriétés de navigation contiennent d’autres entités qui sont associées à cette entité. La propriété Enrollments d’une entité Student :

  • Contient toutes les entités Enrollment associées à cette entité Student.
  • Si une ligne Student spécifique de la base de données a deux lignes Enrollment associées :
    • La propriété de navigation de Enrollments cette entité Student contient ces deux entités Enrollment.

Les lignes Enrollment contiennent la valeur PK d’un étudiant dans la colonne de clé étrangère StudentID (FK).

Si une propriété de navigation peut contenir plusieurs entités :

  • Le type doit être une liste, par exemple ICollection<T>, List<T> ou HashSet<T>.
  • Il est possible d’ajouter, de supprimer et de mettre à jour des entités.

Les relations de navigation plusieurs-à-plusieurs et un-à-plusieurs peuvent contenir plusieurs entités. Quand vous utilisez ICollection<T>, EF crée une collection HashSet<T> par défaut.

L’entité Enrollment

Diagramme de l’entité Enrollment

Dans le dossier Modèles, créez la classe Enrollment avec le code suivant :

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

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

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

La propriété EnrollmentID est la clé primaire. Cette entité utilise le modèle classnameID au lieu de ID seul. L’entité Student a utilisé le modèle ID. Certains développeurs préfèrent utiliser un modèle dans tout le modèle de données. Dans ce tutoriel, la variante montre qu’il est possible d’utiliser l’un ou l’autre des modèles. Un prochain tutoriel montre comment utiliser ID sans nom de classe simplifie l’implémentation de l’héritage dans le modèle de données.

La propriété Grade est un enum. Le ? après la déclaration de type Grade indique que la propriété Gradeaccepte la valeur Null. Une note qui est null est différente d’une note zéro. null signifie qu’une note n’est pas connue ou n’a pas encore été affectée.

La propriété StudentID est une clé étrangère (FK), et la propriété de navigation correspondante est Student. Une entité Enrollment est associée à une entité Student. Par conséquent, la propriété peut seulement détenir une seule entité Student. Cela diffère de la propriété de navigation Student.Enrollments, qui peut détenir plusieurs entités Enrollment.

La propriété CourseID est une clé étrangère (FK), et la propriété de navigation correspondante est Course. Une entité Enrollment est associée à une entité Course.

Entity Framework interprète une propriété comme une propriété FK si elle est nommée <nom de la propriété de navigation><nom de la propriété de clé primaire>. Par exemple, StudentID pour la propriété de navigation Student, puisque la clé primaire (PK) de l’entité Student est ID. Les propriétés FK peuvent également être nommées <nom de propriété de clé primaire>. Par exemple, CourseID parce que la PK de l’entité Course est CourseID.

L’entité Course

Diagramme de l’entité Course

Dans le dossier Modèles, créez la classe Course avec le code suivant :

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

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

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

La propriété Enrollments est une propriété de navigation. Une entité Course peut être associée à un nombre quelconque d’entités Enrollment.

L’attribut DatabaseGenerated est expliqué dans un tutoriel ultérieur. Cet attribut permet d’entrer la PK pour le cours plutôt que de le générer par la base de données.

Créer le contexte de base de données

La classe principale qui coordonne les fonctionnalités d’EF pour un modèle de données déterminé est la classe du contexte de base de données DbContext. Cette classe est créée en dérivant de la classe Microsoft.EntityFrameworkCore.DbContext. La classe dérivée DbContext spécifie les entités qui sont incluses dans le modèle de données. Il est possible de personnaliser certains comportements EF. Dans ce projet, la classe est nommée SchoolContext.

Dans le dossier du projet, créez un dossier nommé Data.

Dans le dossier Données, créez une classe SchoolContext avec le code suivant :

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

Le code précédent crée une propriété DbSet pour chaque jeu d’entités. Dans la terminologie EF :

  • Un jeu d’entités correspond généralement à une table de base de données.
  • Une entité correspond à une ligne dans la table.

Les instructions DbSet<Enrollment> et DbSet<Course> pourraient être omises, cela fonctionnerait de la même façon. EF les inclurait implicitement pour les raisons suivantes :

  • L’entité Student fait référence à l’entité Enrollment.
  • L’entité Enrollment fait référence à l’entité Course.

Quand la base de données est créée, EF crée des tables dont les noms sont identiques aux noms de propriété DbSet. Les noms des propriétés pour les collections sont généralement au pluriel. Par exemple, Students plutôt que Student. Les développeurs ne sont pas tous d’accord sur la nécessité d’utiliser des noms de table au pluriel. Pour ces tutoriels, le comportement par défaut est remplacé en spécifiant des noms de tables au singulier dans le DbContext. Pour ce faire, ajoutez le code en surbrillance suivant après la dernière propriété DbSet.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

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

Inscrivez SchoolContext

ASP.NET Core comprend l’injection de dépendances. Des services, tels que le contexte de base de données EF, sont inscrits avec l’injection de dépendance au démarrage de l’application. Ces services sont affectés aux composants qui les nécessitent, tels que les contrôleurs MVC, par le biais de paramètres de constructeur. Le code de constructeur de contrôleur qui obtient une instance de contexte est montré plus loin dans ce tutoriel.

Pour inscrire SchoolContext en tant que service, ouvrez Startup.cs et ajoutez les lignes en surbrillance à la méthode ConfigureServices.

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ContosoUniversity
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

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

            services.AddControllersWithViews();
        }

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

Ouvrez le fichier appsettings.json et ajoutez une chaîne de connexion comme indiqué dans la balise suivante :

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

Ajouter le filtre d’exception de la base de données

Ajoutez AddDatabaseDeveloperPageExceptionFilter à ConfigureServices comme indiqué dans le code suivant :

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

    services.AddDatabaseDeveloperPageExceptionFilter();

    services.AddControllersWithViews();
}

Le AddDatabaseDeveloperPageExceptionFilter fournit des informations utiles sur les erreurs dans l’environnement de développement.

Base de données locale SQL Server Express

La chaîne de connexion spécifie SQL Server LocalDB. LocalDB est une version allégée du moteur de base de données SQL Server Express. Elle est destinée au développement d’applications, et non à une utilisation en production. LocalDB démarre à la demande et s’exécute en mode utilisateur, ce qui n’implique aucune configuration complexe. Par défaut, LocalDB crée des fichiers de base de données .mdf dans le répertoire C:/Users/<user>.

Initialiser la base de données avec des données de test

EF crée une base de données vide. Dans cette section, une méthode est ajoutée. Elle est appelée après la création de la base de données pour la remplir avec des données de test.

La méthode EnsureCreated est utilisée pour créer automatiquement la base de données. Dans un tutoriel ultérieur, vous verrez comment traiter les modifications des modèles à l’aide des migrations Code First pour modifier le schéma de base de données au lieu de supprimer et de recréer la base de données.

Dans le dossier Données, créez une nouvelle classe nommée DbInitializer avec le code suivant :

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

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

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

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

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

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

Le code précédent vérifie si la base de données existe :

  • Si la base de données n’est pas trouvée ;
    • Elle est créée et chargée avec des données de test. Il charge les données de test dans des tableaux plutôt que des collections List<T> afin d’optimiser les performances.
  • Si la base de données est trouvée, aucune action n’est nécessaire.

Mettez à jour Program.cs à l’aide du code suivant :

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

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

            CreateDbIfNotExists(host);

            host.Run();
        }

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }

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

Program.cs effectue les opérations suivantes au démarrage de l’application :

  • Obtenir une instance de contexte de base de données à partir du conteneur d’injection de dépendance.
  • Appelez la méthode DbInitializer.Initialize .
  • Supprimez le contexte lorsque la méthode Initialize se termine, comme indiqué dans le code suivant :
public static void Main(string[] args)
{
     var host = CreateWebHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<SchoolContext>();
            DbInitializer.Initialize(context);
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while seeding the database.");
        }
    }

    host.Run();
}

Lors de la première exécution de l’application, la base de données est créée et chargée avec des données de test. Dès que le modèle de données change :

  • Supprimez la base de données.
  • Mettez à jour la méthode implantée et démarrez à nouveau avec une nouvelle base de données.

Dans les tutoriels suivants, la base de données est modifiée quand le modèle de données change, sans supprimer et recréer la base de données. Aucune donnée n’est perdue lorsque le modèle de données change.

Créer un contrôleur et des vues

Utilisez le moteur de génération de modèles automatique dans Visual Studio pour ajouter un contrôleur MVC et les vues qu’utilisera EF pour exécuter des requêtes de données et enregistrer les données.

La création automatique de vues et de méthodes d’action CRUD porte le nom de génération de modèles automatique.

  • Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le dossier Controllers, puis choisissez Ajouter > Nouvel élément généré automatiquement.
  • Dans la boîte de dialogue Ajouter un modèle automatique :
    • Sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework.
    • Cliquez sur Add. La boîte de dialogue Ajouter un contrôleur MVC avec vues, utilisant Entity Framework s’affiche : Générer automatiquement des modèles étudiant
    • Dans Classe de modèle, sélectionnez Étudiant.
    • Dans Classe du contexte de données, sélectionnez SchoolContext.
    • Acceptez la valeur par défaut StudentsController comme nom.
    • Cliquez sur Add.

Le moteur de génération de modèles automatique de Visual Studio crée un fichier StudentsController.cs et un ensemble de vues (fichiers *.cshtml) qui fonctionnent avec le contrôleur.

Notez que le contrôleur accepte un SchoolContext comme paramètre de constructeur.

namespace ContosoUniversity.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;

        public StudentsController(SchoolContext context)
        {
            _context = context;
        }

L’injection de dépendance ASP.NET Core s’occupe de la transmission d’une instance de SchoolContext dans le contrôleur. Vous l’avez configuré dans la classe Startup .

Le contrôleur contient une méthode d’action Index, qui affiche tous les étudiants dans la base de données. La méthode obtient la liste des étudiants du jeu d’entités Students en lisant la propriété Students de l’instance de contexte de base de données :

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}

Les éléments de programmation asynchrones dans ce code sont expliqués plus loin dans ce tutoriel.

La vue Views/Students/Index.cshtml affiche cette liste dans un tableau :

@model IEnumerable<ContosoUniversity.Models.Student>

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

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
                <th>
                    @Html.DisplayNameFor(model => model.LastName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.FirstMidName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.EnrollmentDate)
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </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>

Appuyez sur Ctrl+F5 pour exécuter le projet ou choisissez Déboguer > Exécuter sans débogage dans le menu.

Cliquez sur l’onglet Students pour afficher les données de test que la méthode DbInitializer.Initialize a insérées. Selon l’étroitesse de votre fenêtre de navigateur, vous verrez le lien de l’onglet Students en haut de la page ou vous devrez cliquer sur l’icône de navigation dans le coin supérieur droit pour afficher le lien.

Page home étroite de Contoso University

Page d’index des étudiants

Afficher la base de données

Quand l’application est lancée, la méthode DbInitializer.Initialize appelle EnsureCreated. EF a constaté qu’il n’y avait pas de base de données :

  • Il a donc créé une base de données.
  • Le code de méthode Initialize a rempli la base de données avec des données.

Utilisez l’Explorateur d’objets SQL Server (SSOX) pour afficher la base de données dans Visual Studio :

  • Sélectionnez l’Explorateur d’objets SQL Server (SSOX) à partir du menu Affichage de Visual Studio.
  • Dans SSOX, sélectionnez (localdb)\MSSQLLocalDB > Bases de données.
  • Sélectionnez ContosoUniversity1, l’entrée du nom de la base de données qui se trouve dans la chaîne de connexion dans le fichier appsettings.json.
  • Développez le nœud Tables pour afficher les tables de la base de données.

Tables dans SSOX

Cliquez avec le bouton droit sur la table Étudiant, puis cliquez sur Afficher les données pour afficher les données de la table.

Table Student dans SSOX

Les fichiers des base de données *.mdf et *.ldf se trouvent dans le dossier C:\Users\<username> .

Étant donné que EnsureCreated est appelé dans la méthode d’initialiseur qui s’exécute au démarrage de l’application, vous pouvez :

  • Apporter une modification à la classe Student.
  • Supprimez la base de données.
  • Arrêtez, puis démarrez l’application. La base de données est automatiquement recréée pour correspondre à la modification.

Par exemple, si une propriété EmailAddress est ajoutée à la classe Student, une nouvelle colonne EmailAddress se trouve dans la table recréée. La vue n’affiche pas la nouvelle propriété EmailAddress.

Conventions

La quantité de code écrite pour que l’EF crée une base de données complète est minime en raison de l’utilisation des conventions qu’EF emploie :

  • Les noms des propriétés DbSet sont utilisés comme noms de tables. Pour les entités non référencées par une propriété DbSet, les noms des classes d’entités sont utilisés comme noms de tables.
  • Les noms des propriétés d’entités sont utilisés comme noms de colonnes.
  • Les propriétés d’entité nommées ID ou classnameID sont reconnues comme propriétés PK.
  • Une propriété est interprétée comme une propriété FK si elle est nommée <nom de propriété de navigation><nom de propriété PK>. Par exemple, StudentID pour la propriété de navigation Student, puisque la clé primaire (PK) de l’entité Student est ID. Les propriétés FK peuvent également être nommées <nom de propriété de clé primaire>. Par exemple, EnrollmentID puisque la clé primaire (PK) de l’entité Enrollment est EnrollmentID.

Le comportement conventionnel peut être remplacé. Par exemple, les noms des tables peuvent être spécifiés explicitement, comme indiqué plus haut dans ce tutoriel. Les noms de colonnes et n’importe quelle propriété peuvent être définis en tant que PK ou FK (clé primaire ou clé étrangère).

Code asynchrone

La programmation asynchrone est le mode par défaut pour ASP.NET Core et EF Core.

Un serveur web a un nombre limité de threads disponibles et, dans les situations de forte charge, tous les threads disponibles peuvent être utilisés. Quand cela se produit, le serveur ne peut pas traiter de nouvelle requête tant que les threads ne sont pas libérés. Avec le code synchrone, plusieurs threads peuvent être bloqués alors qu’ils n’effectuent en fait aucun travail, car ils attendent que des E/S se terminent. Avec le code asynchrone, quand un processus attend que des E/S se terminent, son thread est libéré afin d’être utilisé par le serveur pour traiter d’autres demandes. Il permet ainsi d’utiliser les ressources serveur plus efficacement, et le serveur peut gérer plus de trafic sans retard.

Le code asynchrone introduit néanmoins une petite surcharge au moment de l’exécution, mais dans les situations de faible trafic, la baisse de performances est négligeable, alors qu’en cas de trafic élevé, l’amélioration potentielle des performances est importante.

Dans le code suivant, async, Task<T>, await et ToListAsync font que le code s’exécute de manière asynchrone.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • Le mot clé async indique au compilateur de générer des rappels pour les parties du corps de la méthode et pour créer automatiquement l’objet Task<IActionResult> qui est renvoyé.
  • Le type de retour Task<IActionResult> représente le travail en cours avec un résultat de type IActionResult.
  • Le mot clé await indique au compilateur de fractionner la méthode en deux parties. La première partie se termine par l’opération qui est démarrée de façon asynchrone. La seconde partie est placée dans une méthode de rappel qui est appelée quand l’opération se termine.
  • ToListAsync est la version asynchrone de la méthode d’extension ToList.

Voici quelques éléments à connaître lors de l’écriture de code asynchrone qui utilise EF :

  • Seules les instructions qui provoquent l’envoi de requêtes ou de commandes vers la base de données sont exécutées de façon asynchrone. Cela inclut, par exemple, ToListAsync, SingleOrDefaultAsync et SaveChangesAsync, mais pas les instructions qui ne font, par exemple, que changer IQueryable, telles que var students = context.Students.Where(s => s.LastName == "Davolio").
  • Un contexte EF n’est pas thread-safe : n’essayez pas d’effectuer plusieurs opérations en parallèle. Lorsque vous appelez une méthode EF asynchrone quelconque, utilisez toujours le mot clé await.
  • Pour tirer profit des meilleures performances du code asynchrone, assurez-vous que tous les packages de bibliothèque utilisés utilisent également du code asynchrone s’ils appellent des méthodes EF qui provoquent l’envoi des requêtes à la base de données.

Pour plus d’informations sur la programmation asynchrone dans .NET, consultez Vue d’ensemble du code asynchrone.

Limiter les entités extraites

Pour plus d’informations sur la limitation du nombre d’entités renvoyées à partir d’une requête, consultez Considérations relatives aux performances.

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.

Passez au tutoriel suivant pour découvrir comment effectuer des opérations CRUD de base (créer, lire, mettre à jour, supprimer).

Ce didacticiel décrit ASP.NET Core MVC et Entity Framework Core avec des contrôleurs et des vues. Razor Pages est un autre modèle de programmation. Pour le nouveau développement, nous recommandons Razor Pages plutôt que MVC avec des contrôleurs et des vues. Consultez la version Razor Pages de ce tutoriel. Chaque tutoriel couvre des sujets que l’autre ne couvre pas :

Ce tutoriel MVC présente certains éléments que le tutoriel Razor Pages ne présente pas :

  • Implémenter l’héritage dans le modèle de données
  • Exécuter des requêtes SQL brutes
  • Utiliser du code dynamique LINQ pour simplifier le code

Voici certains éléments que le tutoriel Razor Pages présente, contrairement à celui-ci :

  • Utiliser la méthode Select pour charger les données associées
  • Bonnes pratiques pour EF.

L’exemple d’application web Contoso University montre comment créer des applications web ASP.NET Core 2.2 MVC à l’aide d’Entity Framework (EF) Core 2.2 et de Visual Studio 2019.

Ce tutoriel n’a pas été mis à jour pour ASP.NET Core 3.1. Il a été mise à jour pour ASP.NET Core 5.0.

L’exemple d’application est un site web pour une université Contoso fictive. Il comprend des fonctionnalités telles que l’admission des étudiants, la création des cours et les affectations des formateurs. Ce document est le premier d’une série de didacticiels qui expliquent comment générer à partir de zéro l’exemple d’application Contoso University.

Prérequis

Dépannage

Si vous rencontrez un problème que vous ne pouvez pas résoudre, vous pouvez généralement trouver la solution en comparant votre code au projet terminé. Pour obtenir la liste des erreurs courantes et comment les résoudre, consultez la section Dépannage du dernier didacticiel de la série. Si vous n’y trouvez pas ce dont vous avez besoin, vous pouvez publier une question sur StackOverflow.com pour ASP.NET Core ou EF Core.

Conseil

Il s’agit d’une série de 10 didacticiels, dont chacun s’appuie sur les opérations réalisées dans les précédents. Pensez à enregistrer une copie du projet à la fin de chaque didacticiel réussi. Ainsi, si vous rencontrez des problèmes, vous pouvez recommencer à la fin du didacticiel précédent au lieu de revenir au début de la série entière.

Application web Contoso University

L’application que vous allez générer dans ces didacticiels est un site web simple d’université.

Les utilisateurs peuvent afficher et mettre à jour les informations relatives aux étudiants, aux cours et aux formateurs. Voici quelques écrans que vous allez créer.

Page d’index des étudiants

Page de modification des étudiants

Créer une application web

  • Ouvrez Visual Studio.

  • Dans le menu Fichier, sélectionnez Nouveau > Projet.

  • Dans le volet gauche, sélectionnez Installé > Visual C# > Web.

  • Sélectionnez le modèle de projet Application web ASP.NET Core.

  • Entrez ContosoUniversity comme nom et cliquez sur OK.

    Boîte de dialogue Nouveau projet

  • Patientez jusqu’à l’affichage de la boîte de dialogue Nouvelle application web ASP.NET Core.

  • Sélectionnez .NET Core, ASP.NET Core 2.2 et le modèle Application web (Model-View-Controller).

  • Vérifiez que l’option Authentification est définie sur Aucune authentification.

  • Sélectionnez OK.

    Boîte de dialogue Nouveau projet ASP.NET Core

Configurer le style du site

Quelques changements basiques permettent de configurer le menu, la mise en page et la page home du site.

Ouvrez Views/Shared/_Layout.cshtml et apportez les changements suivants :

  • Remplacez chaque occurrence de « ContosoUniversity » par « Contoso University ». Il y a trois occurrences.

  • Ajoutez des entrées de menu pour À propos, Étudiants, Cours, Formateurs et Departments, et supprimez l’entrée de menu Privacy.

Les modifications sont mises en surbrillance.

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

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
              crossorigin="anonymous"
              integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
    </environment>
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

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

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
        </script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
        </script>
    </environment>
    <script src="~/js/site.js" asp-append-version="true"></script>

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

Dans Views/Home/Index.cshtml, remplacez le contenu du fichier par le code suivant afin de remplacer le texte sur ASP.NET et MVC par le texte concernant cette application :

@{
    ViewData["Title"] = "Home Page";
}

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

Appuyez sur Ctrl+F5 pour exécuter le projet ou choisissez Déboguer > Exécuter sans débogage dans le menu. Vous voyez la page home avec les onglets des pages que vous allez créer dans ces tutoriels.

Page home de Contoso University

À propos des packages NuGet EF Core

Pour ajouter la prise en charge de EF Core à un projet, installez le fournisseur de bases de données que vous souhaitez cibler. Ce didacticiel utilise SQL Server et le package de fournisseur est Microsoft.EntityFrameworkCore.SqlServer. Ce package étant inclus dans le métapaquet Microsoft.AspNetCore.App, vous n’avez pas besoin de le référencer.

Le package EF SQL Server et ses dépendances (Microsoft.EntityFrameworkCore et Microsoft.EntityFrameworkCore.Relational) fournissent la prise en charge du runtime pour EF. Vous ajouterez un package d’outils ultérieurement, dans le didacticiel Migrations.

Pour obtenir des informations sur les autres fournisseurs de bases de données qui sont disponibles pour Entity Framework Core, consultez Fournisseurs de bases de données.

Créer le modèle de données

Ensuite, vous allez créer des classes d’entités pour l’application Contoso University. Vous commencerez avec les trois entités suivantes.

Diagramme du modèle de données Course-Enrollment-Student

Il existe une relation un-à-plusieurs entre les entités Student et Enrollment, et une relation un-à-plusieurs entre les entités Course et Enrollment. En d’autres termes, un étudiant peut être inscrit dans un nombre quelconque de cours et un cours peut avoir un nombre quelconque d’élèves inscrits.

Dans les sections suivantes, vous allez créer une classe pour chacune de ces entités.

L’entité Student

Diagramme de l’entité Student

Dans le dossier Modèles, créez un fichier de classe nommé Student.cs et remplacez le code du modèle par le code suivant.

using System;
using System.Collections.Generic;

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

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

La propriété ID devient la colonne de clé primaire de la table de base de données qui correspond à cette classe. Par défaut, Entity Framework interprète une propriété nommée ID ou classnameID comme étant la clé primaire.

La propriété Enrollments est une propriété de navigation. Les propriétés de navigation contiennent d’autres entités qui sont associées à cette entité. Dans ce cas, la propriété Enrollments d’un Student entity contient toutes les entités Enrollment associées à l’entité Student. En d’autres termes, si une ligne Student donnée dans la base de données a deux lignes Enrollment associées (lignes qui contiennent la valeur de clé primaire de cet étudiant dans la colonne de clé étrangère StudentID), la propriété de navigation Enrollments de cette entité Student contiendra ces deux entités Enrollment.

Si une propriété de navigation peut contenir plusieurs entités (comme dans des relations plusieurs à plusieurs ou un -à-plusieurs), son type doit être une liste dans laquelle les entrées peuvent être ajoutées, supprimées et mises à jour, telle que ICollection<T>. Vous pouvez spécifier ICollection<T> ou un type tel que List<T> ou HashSet<T>. Si vous spécifiez ICollection<T>, EF crée une collection HashSet<T> par défaut.

L’entité Enrollment

Diagramme de l’entité Enrollment

Dans le dossier Modèles, créez Enrollment.cs et remplacez le code existant par le code suivant :

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

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

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

La propriété EnrollmentID sera la clé primaire. Cette entité utilise le modèle classnameID à la place de ID par lui-même, comme vous l’avez vu dans l’entité Student. En général, vous choisissez un modèle et l’utilisez dans tout votre modèle de données. Ici, la variante illustre que vous pouvez utiliser l’un ou l’autre modèle. Dans un prochain didacticiel, vous verrez comment l’utilisation de l’ID sans classname simplifie l’implémentation de l’héritage dans le modèle de données.

La propriété Grade est un enum. Le point d’interrogation après la déclaration de type Grade indique que la propriété Grade est nullable. Une note (Grade) qui a la valeur Null est différente d’une note égale à zéro : la valeur Null signifie qu’une note n’est pas connue ou n’a pas encore été affectée.

La propriété StudentID est une clé étrangère, et la propriété de navigation correspondante est Student. Une entité Enrollment est associée à une entité Student, donc la propriété peut contenir uniquement une entité Student unique (contrairement à la propriété de navigation Student.Enrollments que vous avez vue précédemment, qui peut contenir plusieurs entités Enrollment).

La propriété CourseID est une clé étrangère, et la propriété de navigation correspondante est Course. Une entité Enrollment est associée à une entité Course.

Entity Framework interprète une propriété comme une propriété de clé étrangère si elle est nommée <navigation property name><primary key property name> (par exemple, StudentID pour la propriété de navigation Student, puisque la clé primaire de l’entité Student est ID). Les propriétés de clé étrangère peuvent également être nommées simplement <primary key property name> (par exemple, CourseID, puisque la clé primaire de l’entité Course est CourseID).

L’entité Course

Diagramme de l’entité Course

Dans le dossier Modèles, créez Course.cs et remplacez le code existant par le code suivant :

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

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

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

La propriété Enrollments est une propriété de navigation. Une entité Course peut être associée à un nombre quelconque d’entités Enrollment.

Nous fournirons plus de détails sur l’attribut DatabaseGenerated dans un didacticiel ultérieur de cette série. En fait, cet attribut vous permet d’entrer la clé primaire pour le cours plutôt que de laisser la base de données la générer.

Créer le contexte de base de données

La classe principale qui coordonne les fonctionnalités d’Entity Framework pour un modèle de données spécifié est la classe de contexte de base de données. Vous créez cette classe en dérivant de la classe Microsoft.EntityFrameworkCore.DbContext. Dans votre code, vous spécifiez les entités qui sont incluses dans le modèle de données. Vous pouvez également personnaliser un certain comportement d’Entity Framework. Dans ce projet, la classe est nommée SchoolContext.

Dans le dossier du projet, créez un dossier nommé Data.

Dans ce dossier Données, créez un nouveau fichier de classe nommé SchoolContext.cs et remplacez le code du modèle par le code suivant :

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

Ce code crée une propriété DbSet pour chaque 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, et une entité correspond à une ligne dans la table.

Vous pourriez avoir omis les instructions DbSet<Enrollment> et DbSet<Course>, et cela fonctionnerait de la même façon. Entity Framework les inclurait implicitement, car l’entité Student référence l’entité Enrollment, et l’entité Enrollment référence l’entité Course.

Quand la base de données est créée, EF crée des tables dont les noms sont identiques aux noms de propriété DbSet. Les noms de propriété pour les collections sont généralement pluriels (Students plutôt que Student), mais les développeurs ne sont pas tous d’accord sur la nécessité d’utiliser des noms de tables au pluriel. Pour ces didacticiels, vous remplacerez le comportement par défaut en spécifiant des noms de tables au singulier dans le contexte DbContext. Pour ce faire, ajoutez le code en surbrillance suivant après la dernière propriété DbSet.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

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

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

Inscrire SchoolContext

ASP.NET Core implémente l’injection de dépendance par défaut. Des services (tels que le contexte de base de données EF) sont inscrits avec l’injection de dépendance au démarrage de l’application. Ces services sont affectés aux composants qui les nécessitent (tels que les contrôleurs MVC) par le biais de paramètres de constructeur. Vous verrez le code de constructeur de contrôleur qui obtient une instance de contexte plus loin dans ce didacticiel.

Pour inscrire SchoolContext en tant que service, ouvrez Startup.cs et ajoutez les lignes en surbrillance à la méthode ConfigureServices.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

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

    services.AddMvc();
}

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

Ajoutez des instructions using pour les espaces de noms ContosoUniversity.Data et Microsoft.EntityFrameworkCore, puis générez le projet.

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;

Ouvrez le fichier appsettings.json et ajoutez une chaîne de connexion comme indiqué dans l’exemple suivant.

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

Base de données locale SQL Server Express

La chaîne de connexion spécifie une base de données SQL Server LocalDB. LocalDB est une version allégée du moteur de base de données SQL Server Express. Elle est destinée au développement d’applications, et non à une utilisation en production. LocalDB démarre à la demande et s’exécute en mode utilisateur, ce qui n’implique aucune configuration complexe. Par défaut, LocalDB crée des fichiers de base de données .mdf dans le répertoire C:/Users/<user>.

Initialiser la base de données avec des données de test

Entity Framework créera une base de données vide pour vous. Dans cette section, vous écrivez une méthode qui est appelée après la création de la base de données pour la remplir avec des données de test.

Là, vous allez utiliser la méthode EnsureCreated pour créer automatiquement la base de données. Dans un didacticiel ultérieur, vous verrez comment traiter les modifications des modèles à l’aide des migrations Code First pour modifier le schéma de base de données au lieu de supprimer et de recréer la base de données.

Dans le dossier Données, créez un nouveau fichier de classe nommé DbInitializer.cs et remplacez le code de modèle par le code suivant, qui entraîne la création d’une base de données, si nécessaire, et charge les données de test dans la nouvelle base de données.

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

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

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

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

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

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

Le code vérifie si des étudiants figurent dans la base de données et, dans la négative, il suppose que la base de données est nouvelle et doit être initialement peuplée avec des données de test. Il charge les données de test dans des tableaux plutôt que des collections List<T> afin d’optimiser les performances.

Dans Program.cs, modifiez la méthode Main pour effectuer les opérations suivantes au démarrage de l’application :

  • Obtenir une instance de contexte de base de données à partir du conteneur d’injection de dépendance.
  • Appeler la méthode de remplissage initial, en lui transmettant le contexte.
  • Supprimer le contexte une fois l’exécution de la méthode de peuplement initial terminée.
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

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

            CreateDbIfNotExists(host);

            host.Run();
        }

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }

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

La première fois que vous exécutez l’application, la base de données est créée et initialement peuplée avec les données de test. Chaque fois que vous modifiez le modèle de données :

  • Supprimez la base de données.
  • Mettez à jour la méthode implantée et démarrez à nouveau avec une nouvelle base de données de la même manière.

Dans les didacticiels suivants, vous verrez comment modifier la base de données quand le modèle de données change, sans supprimer et recréer la base de données.

Créer un contrôleur et des vues

Dans cette section, le moteur de génération de modèles automatique dans Visual Studio est utilisé pour ajouter un contrôleur MVC et les vues qu’utilisera EF pour exécuter des requêtes de données et enregistrer les données.

La création automatique de vues et de méthodes d’action CRUD porte le nom de génération de modèles automatique. La génération de modèles automatique diffère de la génération de code dans la mesure où le code obtenu par génération de modèles automatique est un point de départ que vous pouvez modifier pour prendre en compte vos propres exigences, tandis qu’en général vous ne modifiez pas le code généré. Lorsque vous avez besoin de personnaliser le code généré, vous utilisez des classes partielles ou vous regénérez le code en cas de changements.

  • 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.
  • Dans la boîte de dialogue Ajouter un modèle automatique :
    • Sélectionnez Contrôleur MVC avec vues, utilisant Entity Framework.
    • Cliquez sur Add. La boîte de dialogue Ajouter un contrôleur MVC avec vues, utilisant Entity Framework s’affiche : Générer automatiquement des modèles étudiant
    • Dans Classe de modèle, sélectionnez Student.
    • Dans Classe du contexte de données, sélectionnez SchoolContext.
    • Acceptez la valeur par défaut StudentsController comme nom.
    • Cliquez sur Add.

Le moteur de génération de modèles automatique de Visual Studio crée un fichier StudentsController.cs et un ensemble de vues (fichiers .cshtml) qui fonctionnent avec le contrôleur.

Notez que le contrôleur accepte un SchoolContext comme paramètre de constructeur.

namespace ContosoUniversity.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;

        public StudentsController(SchoolContext context)
        {
            _context = context;
        }

L’injection de dépendance ASP.NET Core s’occupe de la transmission d’une instance de SchoolContext dans le contrôleur. Qui a été configuré dans le fichier Startup.cs.

Le contrôleur contient une méthode d’action Index, qui affiche tous les étudiants dans la base de données. La méthode obtient la liste des étudiants du jeu d’entités Students en lisant la propriété Students de l’instance de contexte de base de données :

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}

Vous découvrirez les éléments de programmation asynchrones dans ce code, plus loin dans ce tutoriel.

La vue Views/Students/Index.cshtml affiche cette liste dans un tableau :

@model IEnumerable<ContosoUniversity.Models.Student>

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

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
                <th>
                    @Html.DisplayNameFor(model => model.LastName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.FirstMidName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.EnrollmentDate)
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </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>

Appuyez sur Ctrl+F5 pour exécuter le projet ou choisissez Déboguer > Exécuter sans débogage dans le menu.

Cliquez sur l’onglet Students pour afficher les données de test que la méthode DbInitializer.Initialize a insérées. Selon l’étroitesse de votre fenêtre de navigateur, vous verrez le lien de l’onglet Students en haut de la page ou vous devrez cliquer sur l’icône de navigation dans le coin supérieur droit pour afficher le lien.

Page home étroite de Contoso University

Page d’index des étudiants

Afficher la base de données

Lorsque vous avez démarré l’application, la méthode DbInitializer.Initialize appelle EnsureCreated. EF a vu qu’il n’y avait pas de base de données et en a donc créé une, puis le reste du code de la méthode Initialize a rempli la base de données avec des données. Vous pouvez utiliser l’Explorateur d’objets SQL Server (SSOX) pour afficher la base de données dans Visual Studio.

Fermez le navigateur.

Si la fenêtre SSOX n’est pas déjà ouverte, sélectionnez-la dans le menu Affichage de Visual Studio.

Dans SSOX, cliquez sur (localdb)\MSSQLLocalDB > Bases de données, puis cliquez sur l’entrée pour le nom de la base de données qui se trouve dans la chaîne de connexion, dans votre fichier appsettings.json.

Développez le nœud Tables pour afficher les tables de la base de données.

Tables dans SSOX

Cliquez avec le bouton droit sur la table Student et cliquez sur Afficher les données pour voir les colonnes qui ont été créées et les lignes qui ont été insérées dans la table.

Table Student dans SSOX

Les fichiers de base de données .mdf et .ldf se trouvent dans le dossier C:\Users<username>.

Étant donné que vous appelez EnsureCreated dans la méthode d’initialiseur qui s’exécute au démarrage de l’application, vous pouvez maintenant apporter une modification à la classe Student, supprimer la base de données ou réexécuter l’application, et la base de données serait automatiquement recréée conformément à votre modification. Par exemple, si vous ajoutez une propriété EmailAddress à la classe Student, vous voyez une nouvelle colonne EmailAddress dans la table recréée.

Conventions

La quantité de code que vous deviez écrire pour qu’Entity Framework puisse créer une base de données complète pour vous est minimale en raison de l’utilisation de conventions ou d’hypothèses effectuées par Entity Framework.

  • Les noms des propriétés DbSet sont utilisés comme noms de tables. Pour les entités non référencées par une propriété DbSet, les noms des classes d’entités sont utilisés comme noms de tables.
  • Les noms des propriétés d’entités sont utilisés comme noms de colonnes.
  • Les propriétés d’entité nommées ID ou classnameID sont reconnues comme propriétés de clé primaire.
  • Une propriété est interprétée comme propriété de clé étrangère si elle se nomme<nom de la propriété de navigation><nom de la propriété de clé primaire> (par exemple StudentID pour la propriété de navigation Student, puisque la clé primaire de l’entité Student est ID). Les propriétés de clé étrangère peuvent également être nommées simplement <nom de la propriété de clé primaire> (par exemple, EnrollmentID, puisque la clé primaire de l’entité Enrollment est EnrollmentID).

Le comportement conventionnel peut être remplacé. Par exemple, vous pouvez spécifier explicitement les noms de tables, comme vous l’avez vu précédemment dans ce didacticiel. De plus, vous pouvez définir des noms de colonne et définir une propriété quelconque en tant que clé primaire ou clé étrangère, comme vous le verrez dans un didacticiel ultérieur dans cette série.

Code asynchrone

La programmation asynchrone est le mode par défaut pour ASP.NET Core et EF Core.

Un serveur web a un nombre limité de threads disponibles et, dans les situations de forte charge, tous les threads disponibles peuvent être utilisés. Quand cela se produit, le serveur ne peut pas traiter de nouvelle requête tant que les threads ne sont pas libérés. Avec le code synchrone, plusieurs threads peuvent être bloqués alors qu’ils n’effectuent en fait aucun travail, car ils attendent que des E/S se terminent. Avec le code asynchrone, quand un processus attend que des E/S se terminent, son thread est libéré afin d’être utilisé par le serveur pour traiter d’autres demandes. Il permet ainsi d’utiliser les ressources serveur plus efficacement, et le serveur peut gérer plus de trafic sans retard.

Le code asynchrone introduit néanmoins une petite surcharge au moment de l’exécution, mais dans les situations de faible trafic, la baisse de performances est négligeable, alors qu’en cas de trafic élevé, l’amélioration potentielle des performances est importante.

Dans le code suivant, le mot clé async, la valeur renvoyée Task<T>, le mot clé await et la méthode ToListAsync provoquent l’exécution asynchrone du code.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • Le mot clé async indique au compilateur de générer des rappels pour les parties du corps de la méthode et pour créer automatiquement l’objet Task<IActionResult> qui est renvoyé.
  • Le type de retour Task<IActionResult> représente le travail en cours avec un résultat de type IActionResult.
  • Le mot clé await indique au compilateur de fractionner la méthode en deux parties. La première partie se termine par l’opération qui est démarrée de façon asynchrone. La seconde partie est placée dans une méthode de rappel qui est appelée quand l’opération se termine.
  • ToListAsync est la version asynchrone de la méthode d’extension ToList.

Voici quelques éléments à connaître lorsque vous écrivez un code asynchrone qui utilise Entity Framework :

  • Seules les instructions qui provoquent l’envoi de requêtes ou de commandes vers la base de données sont exécutées de façon asynchrone. Cela inclut, par exemple, ToListAsync, SingleOrDefaultAsync et SaveChangesAsync, mais pas les instructions qui ne font, par exemple, que changer IQueryable, telles que var students = context.Students.Where(s => s.LastName == "Davolio").
  • Un contexte EF n’est pas thread-safe : n’essayez pas d’effectuer plusieurs opérations en parallèle. Lorsque vous appelez une méthode EF asynchrone quelconque, utilisez toujours le mot clé await.
  • Si vous souhaitez tirer profit des meilleures performances du code asynchrone, assurez-vous que tous les packages de bibliothèque que vous utilisez (par exemple pour changer de page) utilisent également du code asynchrone s’ils appellent des méthodes Entity Framework qui provoquent l’envoi des requêtes à la base de données.

Pour plus d’informations sur la programmation asynchrone dans .NET, consultez Vue d’ensemble du code asynchrone.

Étapes suivantes

Passez au tutoriel suivant pour découvrir comment effectuer des opérations CRUD de base (créer, lire, mettre à jour, supprimer).