Tutoriel : Utiliser des procédures asynchrones et stockées avec EF dans une application MVC ASP.NET
Dans les didacticiels précédents, vous avez appris à lire et à mettre à jour des données à l’aide du modèle de programmation synchrone. Dans ce tutoriel, vous voyez comment implémenter le modèle de programmation asynchrone. Le code asynchrone peut améliorer l’exécution d’une application, car elle utilise mieux les ressources du serveur.
Dans ce tutoriel, vous allez également voir comment utiliser des procédures stockées pour les opérations d’insertion, de mise à jour et de suppression sur une entité.
Enfin, vous redéployez l’application sur Azure, ainsi que toutes les modifications de base de données que vous avez implémentées depuis la première fois que vous avez déployé.
Les illustrations suivantes montrent quelques-unes des pages que vous allez utiliser.
Dans ce tutoriel, vous allez :
- En savoir plus sur le code asynchrone
- Créer un contrôleur de service
- Utiliser des procédures stockées
- Déployer dans Azure
Prérequis
Pourquoi utiliser du code asynchrone
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. Par conséquent, le code asynchrone permet aux ressources serveur d’être utilisées plus efficacement et le serveur est activé pour gérer plus de trafic sans retard.
Dans les versions antérieures de .NET, l’écriture et le test du code asynchrone étaient complexes, sujets aux erreurs et difficiles à déboguer. Dans .NET 4.5, l’écriture, le test et le débogage du code asynchrone sont tellement plus faciles que vous devez généralement écrire du code asynchrone, sauf si vous n’avez pas de raison de ne pas le faire. Le code asynchrone introduit une petite quantité de surcharge, mais pour les situations de faible trafic, l’accès aux performances est négligeable, tandis que pour les situations de trafic élevé, l’amélioration potentielle des performances est importante.
Pour plus d’informations sur la programmation asynchrone, consultez La prise en charge asynchrone de .NET 4.5 pour éviter les appels bloquants.
Créer un contrôleur de service
Créez un contrôleur de service de la même façon que les contrôleurs précédents, sauf cette fois, activez la case à cocher Utiliser les actions du contrôleur asynchrone.
Les points forts suivants montrent ce qui a été ajouté au code synchrone de la Index
méthode pour le rendre asynchrone :
public async Task<ActionResult> Index()
{
var departments = db.Departments.Include(d => d.Administrator);
return View(await departments.ToListAsync());
}
Quatre modifications ont été appliquées pour permettre à la requête de base de données Entity Framework de s’exécuter de manière asynchrone :
- La méthode est marquée avec le
async
mot clé, qui indique au compilateur de générer des rappels pour les parties du corps de la méthode et de créer automatiquement l’objetTask<ActionResult>
retourné. - Le type de retour a été remplacé par
ActionResult
Task<ActionResult>
. LeTask<T>
type représente le travail en cours avec un résultat de typeT
. - Le
await
mot clé a été appliqué à l’appel de service web. Lorsque le compilateur voit ce mot clé, en arrière-plan, il fractionne la méthode en deux parties. La première partie se termine par l’opération démarrée de manière asynchrone. La deuxième partie est placée dans une méthode de rappel appelée une fois l’opération terminée. - La version asynchrone de la méthode d’extension
ToList
a été appelée.
Pourquoi l’instruction departments.ToList
est-elle modifiée, mais pas l’instruction departments = db.Departments
? La raison est que seules les instructions qui provoquent l’envoi de requêtes ou de commandes à la base de données sont exécutées de manière asynchrone. L’instruction departments = db.Departments
configure une requête, mais la requête n’est pas exécutée tant que la ToList
méthode n’est pas appelée. Par conséquent, seule la ToList
méthode est exécutée de façon asynchrone.
Dans la Details
méthode et les HttpGet
Edit
Delete
méthodes, la Find
méthode est celle qui provoque l’envoi d’une requête à la base de données, c’est-à-dire la méthode qui est exécutée de manière asynchrone :
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Department department = await db.Departments.FindAsync(id);
if (department == null)
{
return HttpNotFound();
}
return View(department);
}
Dans le , HttpPost Edit
et DeleteConfirmed
les méthodes, il s’agit de l’appel SaveChanges
Create
de méthode qui provoque l’exécution d’une commande, et non des instructions telles que db.Departments.Add(department)
celles qui entraînent la modification d’entités en mémoire uniquement.
public async Task<ActionResult> Create(Department department)
{
if (ModelState.IsValid)
{
db.Departments.Add(department);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
Ouvrez Views\Department\Index.cshtml et remplacez le code du modèle par le code suivant :
@model IEnumerable<ContosoUniversity.Models.Department>
@{
ViewBag.Title = "Departments";
}
<h2>Departments</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Budget)
</th>
<th>
@Html.DisplayNameFor(model => model.StartDate)
</th>
<th>
Administrator
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Budget)
</td>
<td>
@Html.DisplayFor(modelItem => item.StartDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Administrator.FullName)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
@Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
</td>
</tr>
}
</table>
Ce code modifie le titre de l’index aux services, déplace le nom de l’administrateur à droite et fournit le nom complet de l’administrateur.
Dans les affichages Créer, Supprimer, Détails et Modifier, remplacez la légende du InstructorID
champ par « Administrateur » de la même façon que vous avez remplacé le champ nom du service par « Département » dans les affichages Cours.
Dans les vues Créer et modifier, utilisez le code suivant :
<label class="control-label col-md-2" for="InstructorID">Administrator</label>
Dans les vues Supprimer et Détails, utilisez le code suivant :
<dt>
Administrator
</dt>
Exécutez l’application, puis cliquez sur l’onglet Services .
Tout fonctionne de la même façon que dans les autres contrôleurs, mais dans ce contrôleur, toutes les requêtes SQL s’exécutent de manière asynchrone.
Voici quelques éléments à prendre en compte lorsque vous utilisez la programmation asynchrone avec Entity Framework :
- Le code asynchrone n’est pas thread-safe. En d’autres termes, n’essayez pas d’effectuer plusieurs opérations en parallèle à l’aide de la même instance de contexte.
- 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.
Utiliser des procédures stockées
Certains développeurs et administrateurs de base de données préfèrent utiliser des procédures stockées pour l’accès à la base de données. Dans les versions antérieures d’Entity Framework, vous pouvez récupérer des données à l’aide d’une procédure stockée en exécutant une requête SQL brute, mais vous ne pouvez pas demander à EF d’utiliser des procédures stockées pour les opérations de mise à jour. Dans EF 6, il est facile de configurer Code First pour utiliser des procédures stockées.
Dans DAL\SchoolContext.cs, ajoutez le code mis en surbrillance à la
OnModelCreating
méthode.protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Entity<Course>() .HasMany(c => c.Instructors).WithMany(i => i.Courses) .Map(t => t.MapLeftKey("CourseID") .MapRightKey("InstructorID") .ToTable("CourseInstructor")); modelBuilder.Entity<Department>().MapToStoredProcedures(); }
Ce code indique à Entity Framework d’utiliser des procédures stockées pour les opérations d’insertion, de mise à jour et de suppression sur l’entité
Department
.Dans la console Gestion des packages, entrez la commande suivante :
add-migration DepartmentSP
Ouvrez migrations\<timestamp>_DepartmentSP.cs pour afficher le code dans la
Up
méthode qui crée des procédures stockées Insert, Update et Delete :public override void Up() { CreateStoredProcedure( "dbo.Department_Insert", p => new { Name = p.String(maxLength: 50), Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"), StartDate = p.DateTime(), InstructorID = p.Int(), }, body: @"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID]) VALUES (@Name, @Budget, @StartDate, @InstructorID) DECLARE @DepartmentID int SELECT @DepartmentID = [DepartmentID] FROM [dbo].[Department] WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity() SELECT t0.[DepartmentID] FROM [dbo].[Department] AS t0 WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID" ); CreateStoredProcedure( "dbo.Department_Update", p => new { DepartmentID = p.Int(), Name = p.String(maxLength: 50), Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"), StartDate = p.DateTime(), InstructorID = p.Int(), }, body: @"UPDATE [dbo].[Department] SET [Name] = @Name, [Budget] = @Budget, [StartDate] = @StartDate, [InstructorID] = @InstructorID WHERE ([DepartmentID] = @DepartmentID)" ); CreateStoredProcedure( "dbo.Department_Delete", p => new { DepartmentID = p.Int(), }, body: @"DELETE [dbo].[Department] WHERE ([DepartmentID] = @DepartmentID)" ); }
Dans la console Gestion des packages, entrez la commande suivante :
update-database
Exécutez l’application en mode débogage, cliquez sur l’onglet Services , puis cliquez sur Créer.
Entrez les données d’un nouveau service, puis cliquez sur Créer.
Dans Visual Studio, examinez les journaux dans la fenêtre Sortie pour voir qu’une procédure stockée a été utilisée pour insérer la nouvelle ligne Department.
Code First crée des noms de procédure stockée par défaut. Si vous utilisez une base de données existante, vous devrez peut-être personnaliser les noms des procédures stockées afin d’utiliser des procédures stockées déjà définies dans la base de données. Pour plus d’informations sur la procédure à suivre, consultez La première insertion/mise à jour/suppression des procédures stockées entity Framework Code.
Si vous souhaitez personnaliser ce que font les procédures stockées générées, vous pouvez modifier le code généré pour la méthode de migration Up
qui crée la procédure stockée. De cette façon, vos modifications sont reflétées chaque fois que cette migration est exécutée et sont appliquées à votre base de données de production lorsque les migrations s’exécutent automatiquement en production après le déploiement.
Si vous souhaitez modifier une procédure stockée existante créée dans une migration précédente, vous pouvez utiliser la commande Add-Migration pour générer une migration vide, puis écrire manuellement du code qui appelle la méthode AlterStoredProcedure .
Déployer dans Azure
Cette section nécessite que vous ayez terminé la section Facultatif Déploiement de l’application sur Azure dans le didacticiel Migrations et déploiement de cette série. Si vous avez rencontré des erreurs de migration que vous avez résolues en supprimant la base de données dans votre projet local, ignorez cette section.
Dans l’Explorateur de solutions de Visual Studio, cliquez avec le bouton droit sur le projet, puis dans le menu contextuel, sélectionnez Publier.
Cliquez sur Publier.
Visual Studio déploie l’application sur Azure et l’application s’ouvre dans votre navigateur par défaut, en cours d’exécution dans Azure.
Testez l’application pour vérifier qu’elle fonctionne.
La première fois que vous exécutez une page qui accède à la base de données, Entity Framework exécute toutes les méthodes de migration
Up
requises pour mettre la base de données à jour avec le modèle de données actuel. Vous pouvez maintenant utiliser toutes les pages web que vous avez ajoutées depuis la dernière fois que vous avez déployée, y compris les pages de service que vous avez ajoutées dans ce didacticiel.
Obtenir le code
Ressources supplémentaires
Vous trouverez des liens vers d’autres ressources Entity Framework dans le ASP.NET Accès aux données - Ressources recommandées.
Étapes suivantes
Dans ce tutoriel, vous allez :
- En savoir plus sur le code asynchrone
- Création d’un contrôleur de service
- Procédures stockées utilisées
- Déployé sur Azure
Passez à l’article suivant pour apprendre à gérer les conflits lorsque plusieurs utilisateurs mettent à jour la même entité en même temps.