Événement
31 mars, 23 h - 2 avr., 23 h
L’événement de la communauté Microsoft Fabric, Power BI, SQL et AI ultime. 31 mars au 2 avril 2025.
S’inscrire maintenantCe navigateur n’est plus pris en charge.
Effectuez une mise à niveau vers Microsoft Edge pour tirer parti des dernières fonctionnalités, des mises à jour de sécurité et du support technique.
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 :
Voici certains éléments que le tutoriel Razor Pages présente, contrairement à celui-ci :
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.
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.
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.
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.
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 :
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é.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 :
ContosoUniversity
par Contoso University
. Il y a trois occurrences.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">
© 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 »</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 »</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.
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.
Les classes d’entité suivantes sont créées pour cette application :
Les entités précédentes ont les relations suivantes :
Student
et Enrollment
. Un étudiant peut être inscrit à autant de cours qu’il le souhaite.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.
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
:
Enrollment
associées à cette entité Student
.Student
spécifique de la base de données a deux lignes Enrollment
associées : 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 :
ICollection<T>
, List<T>
ou HashSet<T>
.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.
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é Grade
accepte 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
.
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.
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 :
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 :
Student
fait référence à l’entité Enrollment
.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");
}
}
}
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": "*"
}
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.
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>
.
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 :
List<T>
afin d’optimiser les performances.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 :
DbInitializer.Initialize
.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 :
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.
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.
Controllers
, puis choisissez Ajouter > Nouvel élément généré automatiquement.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.
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 :
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 :
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
.Cliquez avec le bouton droit sur la table Étudiant, puis cliquez sur Afficher les données pour afficher les données de la table.
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 :
Student
.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
.
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 :
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.ID
ou classnameID
sont reconnues comme propriétés PK.<
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).
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());
}
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é.Task<IActionResult>
représente le travail en cours avec un résultat de type IActionResult
.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 :
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")
.await
.Pour plus d’informations sur la programmation asynchrone dans .NET, consultez Vue d’ensemble du code asynchrone.
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.
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 :
Voici certains éléments que le tutoriel Razor Pages présente, contrairement à celui-ci :
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.
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.
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.
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.
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.
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">
© 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 »</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 »</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.
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.
Ensuite, vous allez créer des classes d’entités pour l’application Contoso University. Vous commencerez avec les trois entités suivantes.
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.
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.
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
).
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.
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.
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"
}
}
}
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>
.
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 :
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 :
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.
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.
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.
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.
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.
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.
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.
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.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.
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());
}
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é.Task<IActionResult>
représente le travail en cours avec un résultat de type IActionResult
.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 :
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")
.await
.Pour plus d’informations sur la programmation asynchrone dans .NET, consultez Vue d’ensemble du code asynchrone.
Passez au tutoriel suivant pour découvrir comment effectuer des opérations CRUD de base (créer, lire, mettre à jour, supprimer).
Commentaires sur ASP.NET Core
ASP.NET Core est un projet open source. Sélectionnez un lien pour fournir des commentaires :
Événement
31 mars, 23 h - 2 avr., 23 h
L’événement de la communauté Microsoft Fabric, Power BI, SQL et AI ultime. 31 mars au 2 avril 2025.
S’inscrire maintenantFormation
Module
Utiliser une base de données avec une API minimale, Entity Framework Core et ASP.NET Core - Training
Découvrez comment ajouter une base de données à une application API minimale.