Le Entity Framework Core est une popularité ORM (Object-Relational Mapper) pour les applications .NET, permettant aux développeurs de travailler avec les bases de données en utilisant des objets .NET. Il peut être utilisé avec de nombreux types de bases de données, y compris MongoDB.

Dans cet article, vous apprendrez comment utiliser Entity Framework Core avec MongoDB. Cet article couvre les bases, explique les avantages et fournit un tutoriel pas à pas. Que vous soyez nouveau à MongoDB ou Entity Framework Core, ou juste cherchant à intégrer ces outils dans vos projets .NET, ce guide vous aidera à briser le fossé entre les bases de données relationnelles et les bases de données NoSQL.

L’article débute avec une brève introduction à MongoDB ainsi qu’une introduction à Entity Framework Core de Microsoft. Ensuite, il couvre la manière d’utiliser le fournisseur MongoDB EF Core. Après avoir passé à travers des détails techniques avec quelques exemples de base, vous creer une projet complet avec MongoB et Entity Framework Core pour voir comment tout fonctionne ensemble. Le projet utilisera des données d’exemple de MongoDB Atlas pour créer un système de réservation de restaurants.

Il existe également une version vidéo de cet article que vous pouvez visionner sur la chaîne YouTube freeCodeCamp.org.

Introduction à MongoDB

MongoDB est une base de données NoSQL populaire conçue pour gérer de grandes quantités de données et offrir une performance élevée, une scalabilité et une flexibilité. Contrairement aux bases de données relationnelles traditionnelles, MongoDB stocke les données dans des documents flexibles, de type JSON. Cette approche orientée document permet le stockage de structures de données complexes de manière naturelle et intuitive.

Dans MongoDB, les données sont stockées dans des collections, qui ressemblent aux tables des bases de données relationnelles mais sans schéma fixe. Cela signifie que vous pouvez avoir des documents avec différentes structures dans la même collection. Cette flexibilité est l’une des principales avancées de MongoDB, en particulier lorsque vous traitez des données non structurées ou semi-structurées.

Examinons un exemple de document MongoDB. Imaginez que nous avons une collection appelée users qui stocke des informations sur les utilisateurs d’une application. Voici ce qu’un document typique pourrait ressembler :

{
    "_id": "12345",
    "name": "John Doe",
    "email": "[email protected]",
    "age": 30,
    "address": {
        "street": "123 Main St",
        "city": "Anytown",
        "state": "CA",
        "zip": "12345"
    },
    "hobbies": ["reading", "travelling", "coding"]
}

Dans ce document, nous avons différents champs tels que name, email, age et address. Le champ address en tant que document imbriqué contient plusieurs sous-champs tels que street, city, state et zip. De plus, le champ hobbies est un tableau de chaînes de caractères.

Bien que cela ressemble à du JSON, MongoDB stocke les données dans un format binaire appelé BSON (Binary JSON). BSON étend le modèle JSON pour fournir des types de données additionnels, tels que les entiers, les flottants, les dates et les données binaires. Ce format binaire est optimisé pour la performance et la flexibilité, ce qui permet à MongoDB de stocker et de récupérer les données de manière efficiente.

Une autre fonction importante de MongoDB est sa capacité à scaler horizontalement. Cela signifie que vous pouvez distribuer vos données sur plusieurs serveurs, ce qui facilite la gestion de jeux de données importants et l’assurance de haute disponibilité. MongoDB offre également de riches requêtes, l’indexation et l’agrégation, ce qui en fait une puissante arme pour une large gamme d’applications.

Par exemple, vous pouvez exécuter une requête pour trouver tous les utilisateurs qui vivent dans une ville spécifique :

db.users.find({ "address.city": "Anytown" })

Vous pouvez également trouver des utilisateurs ayant une passion précise :

db.users.find({ "hobbies": "coding" })

MongoDB est largement utilisé dans diverses industries, depuis le commerce électronique et la gestion du contenu jusqu’à l’analyse en temps réel et aux applications Internet des objets (IoT). Sa flexibilité et sa scalabilité en font un excellent choix pour les applications modernes qui doivent gérer des données diverses et dynamiques.

Maintenant que nous avons une base de connaissance de base sur ce que est MongoDB et pourquoi il est populaire, passons à un autre outil essentiel dans notre stack technique : le Entity Framework Core de Microsoft.

Introduction au Entity Framework Core de Microsoft

Entity Framework Core, souvent abrégé en EF Core, est un mappeur objet-base de données moderne pour .NET. Il permet aux développeurs de travailler avec une base de données en utilisant des objets .NET, éliminant la nécessité de la plupart du code de connexion aux données que les développeurs écrivent généralement.

EF Core est une version légère, extensible et multiplateforme de la populaire technologie de connexion aux données Entity Framework (EF). Elle supporte une variété de moteurs de base de données, y compris SQL Server, SQLite et MongoDB.

L’un des principaux avantages de l’utilisation d’EF Core est qu’il permet aux développeurs de travailler avec les données de manière plus intuitive et orientée objet. Au lieu d’écrire des requêtes SQL brutes, vous pouvez interagir avec votre base de données en utilisant LINQ (Language Integrated Query) et des classes fortement typées.

Faisons une petite démonstration. Supposons qu’ nous avons une classe Product :

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Cela est relativement simple avec seulement trois champs. En utilisant EF Core, vous pouvez créer une classe de contexte qui représente une session avec la base de données et inclut un DbSet pour chaque type d’entité que vous souhaitez interroger ou enregistrer :

public class AppDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)   
    {
        optionsBuilder.Use<Your_SQL_Database_function>("YourConnectionStringHere");
    }
}

Ce code définit une classe nommée AppDbContext qui hérite de la classe DbContext de Entity Framework Core. Cette classe est utilisée pour interagir avec la base de données. Dans cette classe, il y a une propriété de type DbSet<Product> nommée Products, qui représente une collection d’entités de type Product et correspond à une table nommée Products dans la base de données. La méthode OnConfiguring est surchargée pour configurer la connexion à la base de données ; vous pouvez spécifier diverses bases de données en tant que fournisseur de base de données. Cette méthode utilise un optionsBuilder pour configurer la connexion avec un placeur pour la chaîne de connexion réelle de la base de données. Cette chaîne de connexion devrait être remplacée par la véritable chaîne contenant les détails nécessaires pour se connecter à la base de données. Lors de la création d’une instance de AppDbContext dans l’application, elle utilise cette configuration pour effectuer des opérations telles que les requêtes ou la sauvegarde d’entités de type Product dans la table Products.

Avec ce dispositif, vous pouvez effectuer des opérations CRUD (Créer, Lire, Mettre à jour, Supprimer) en utilisant EF Core. Par exemple, pour ajouter un nouveau produit à la base de données, vous pouvez utiliser ce code.

using (var context = new AppDbContext())
{
    var product = new Product { Name = "Laptop", Price = 999.99M };
    context.Products.Add(product);
    context.SaveChanges();
}

Ce code montre comment ajouter un nouveau produit à la base de données en utilisant Entity Framework Core. Une instance de AppDbContext est créée, et à l’intérieur de ce contexte, un nouvel objet Product est instancié avec le nom « Laptop » et un prix de 999,99. Ce nouveau produit est ensuite ajouté à la collection Products gérée par AppDbContext. Enfin, la méthode SaveChanges est appelée pour enregistrer les modifications dans la base de données, insérant effectivement le nouveau produit dans la table Products.

Pour récupérer des produits, vous pouvez utiliser LINQ :

using (var context = new AppDbContext())
{
    var products = context.Products.Where(p => p.Price > 500).ToList();
    foreach (var product in products)
    {
        Console.WriteLine($"Product: {product.Name}, Price: {product.Price}");  
    }
}

Ce code montre comment récupérer les données de la base de données en utilisant Entity Framework Core. Une instance de AppDbContext est créée, et à l’intérieur de ce contexte, une requête est effectuée pour récupérer tous les produits avec un prix supérieur à 500. Les résultats sont stockés dans une liste nommée products. Ensuite, un boucle itère à travers chaque produit dans la liste, imprimant le nom et le prix de chaque produit sur la console.

EF Core s’occupe de traduire ces requêtes LINQ en les commandes SQL appropriées pour votre base de données, ce qui simplifie l’accès aux données et le maintien.

EF Core offre également des fonctionnalités avancées telles que le suivi des modifications, le chargement différé et les migrations, qui vous aident à gérer les modifications du schéma de la base de données au fil du temps.

En résumé, EF Core est une puissante ORM qui simplifie l’accès aux données dans les applications .NET en vous permettant de travailler avec vos données en utilisant des objets .NET et LINQ. Sa prise en charge de multiples moteurs de base de données et son extensibilité en font une solution polyvalente pour une large gamme d’applications.

D’abord, nous verrons comment le fournisseur MongoDB EF Core brise le fossé entre MongoDB et EF Core, ce qui nous permet d’utiliser les patterns EF Core familiers avec une base de données MongoDB.

Comment le fournisseur MongoDB EF Core brise le fossé

Le fournisseur MongoDB Entity Framework Core (EF Core) est une toolbox qui permet aux développeurs d’utiliser MongoDB avec Entity Framework Core, en combinant la flexibilité de MongoDB avec les patterns d’API et de conception familiers d’EF Core. Ce fournisseur vous permet d’utiliser MongoDB en utilisant les mêmes méthodologies de first-code (code-first) et de requêtes LINQ que vous utiliseriez avec les bases de données relationnelles, simplifiant ainsi le développement et réduisant la pente d’apprentissage pour ceux qui sont déjà familiers avec EF Core.

Le fournisseur MongoDB EF Core brise le fossé entre MongoDB et EF Core en supportant les opérations CRUD de base, les requêtes LINQ et les documents imbriqués, entre autres fonctionnalités. Voici quelques capacités clés :

  1. Flux de travail first-code : Vous pouvez définir vos modèles de données en C# et utiliser EF Core pour générer le schéma MongoDB, plutôt que de commencer avec le schéma de base de données et de générer du code à partir de celui-ci. Cela est particulièrement utile pour les développeurs qui préfèrent gérer leur structure de base de données via le code.

  2. Opérations CRUD: Le fournisseur prend en charge les opérations basiques de création, de lecture, de mise à jour et de suppression. Par exemple, vous pouvez ajouter un nouvel enregistrement à la base de données en utilisant le même code que nous avons vu précédemment:

     using (var contexte = new AppDbContext())
     {
         var produit = new Product { Nom = "Laptop", Prix = 999.99M };
         contexte.Produits.Add(produit);
         contexte.SaveChanges();
     }
    
  3. Support de requêtes LINQ : Vous pouvez utiliser LINQ pour effectuer des requêtes sur MongoDB, ce qui vous permet de tirer parti de vos connaissances existantes en C# et .NET pour interagir avec la base de données.

     using (var context = new AppDbContext())
     {
         var products = context.Products.Where(p => p.Price > 500).ToList();
         foreach (var product in products)
         {
             Console.WriteLine($"Product: {product.Name}, Price: {product.Price}");
         }
     }
    
  4. Suivi des modifications : Les capacités de suivi des modifications d’EF Core sont prises en charge, ce qui permet la détection automatique et la sauvegarde des modifications apportées à vos entités de données.

  5. Documents imbriqués : Le fournisseur supporte les documents imbriqués, ce qui vous permet de stocker les données liées dans un seul document, ce qui est un pattern commun dans MongoDB.

  6. Mappage de classes et sérialisation : Vos classes C# sont mapées vers les collections MongoDB, avec le support de divers types de données et de réglages de sérialisation pour s’assurer que les données sont stockées correctement.

Modélisation des données et opérations CRUD à l’aide de MongoDB Atlas

Maintenant, nous allons passer rapidement sur un exemple sur la manière d’utiliser le fournisseur MongoDB EF Core. Mais bientôt, nous créerons un projet complet dans Visual Studio Code pour que vous puissiez voir tout dans son contexte.

Dans cette section, nous explorerons comment définir des modèles de données et effectuer des opérations CRUD (Créer, Lire, Mettre à jour, Supprimer) en utilisant le fournisseur MongoDB Entity Framework Core (EF) avec MongoDB Atlas. Cette intégration permet de tirer parti de la flexibilité de MongoDB en utilisant les patrons familiers d’EF Core.

Configurer votre environnement

Pour démarrer, vous devez ajouter les packages NuGet nécessaires à votre projet :

dotnet add package MongoDB.EntityFrameworkCore

Le package MS EF Core et le pilote MongoDB en C# sont ajoutés en tant que dépendances lorsque vous ajoutez le package de fournisseur MongoDB EF Core. Ces packages permettent à votre application d’interagir avec MongoDB à travers EF Core, en utilisant les mêmes définitions de contexte et d’entités que vous utiliseriez avec une base de données relationnelle.

Configurer MongoDB Atlas

Avant de pouvoir effectuer des opérations CRUD, vous devez configurer un cluster MongoDB Atlas et connecter votre application à celui-ci.

Voici les étapes. Notez que nous passerons en revue ces points dans le détail lors de la création du projet bientôt.

  1. Créer un compte MongoDB Atlas : Inscrivez-vous pour un compte gratuit sur MongoDB Atlas.

  2. Créer un cluster : Configurer un nouveau cluster. MongoDB Atlas offre une gamme gratuite parfaite pour le développement et les applications à petite échelle.

  3. Obtenir la chaîne de connexion : Obtenez votre chaîne de connexion depuis le tableau de bord de MongoDB Atlas. Elle ressemblera à ce qui suit :

     mongodb+srv://<username>:<password>@cluster0.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
    

Définition du modèle de données

Définissez une classe à utiliser comme modèle pour votre entité. Dans cet exemple, nous créerons une classe Customer :

public class Customer
{
    public ObjectId Id { get; set; }
    public String Name { get; set; }
    public String Order { get; set; }
}

Cette classe Customer représente la structure des documents stockés dans la collection MongoDB.

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

Pour commencer à utiliser Entity Framework Core, créez une classe de contexte héritant de DBContext. L’instance de la classe dérivée DbContext représente une session de base de données et est utilisée pour effectuer des requêtes et enregistrer des instances de vos entités.

La classe DBContext expose des propriétés de DBSet qui spécifient les entités avec lesquelles vous pouvez interagir en utilisant ce contexte.

Cet exemple crée une instance de classe dérivée de DBContext et spécifie l’objet Customer comme propriété de DBSet :

public class MyDbContext : DbContext
{
    public DbSet<Customer> Customers { get; init; }

    public MyDbContext(DbContextOptions options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Customer>().ToCollection("customers");
    }
}

Flux de travail de la première classe de code

Avec le fournisseur MongoDB EF, vous pouvez utiliser un flux de travail de la première classe de code. Cela signifie que vous définissez d’abord vos classes, et EF Core gère la création et la gestion du schéma sous-jacent MongoDB. Cela est particulièrement utile pour MongoDB, qui n’impose pas de schéma, permettant des structures de données flexibles et dynamiques.

Utiliser MongoDB

Une fois que nous avons créé une classe DBContext, nous devons construire un objet DbContextOptionsBuilder et appeler sa méthode UseMongoDB(). Cette méthode prend deux paramètres : une instance de MongoClient et le nom de la base de données qui contient les collections avec lesquelles vous travaillez.

La méthode UseMongoDB() retourne un objet DbContextOptions. Transmettez la propriété Options the object to the constructor for your DBContext class.

var mongoClient = new MongoClient("<Your MongoDB Connection URI>");

var dbContextOptions =
    new DbContextOptionsBuilder<MyDbContext>().UseMongoDB(mongoClient, "<Database Name");  

var db = new MyDbContext(dbContextOptions.Options);

Opérations CRUD

Maintenant, voyons comment coder les opérations CRUD. Nous ne nous concentrerons que sur chaque opération individuellement.

Opération de création

Pour créer un nouvel document dans MongoDB, vous utilisez la méthode Add sur le DbSet et appelez SaveChanges. Voici un exemple de création de nouvel client :

using (var context = new MyDbContext(options))
{
    var customer = new Customer { Name = "Beau Carnes", Order = "Laptop" };
    context.Customers.Add(customer);
    context.SaveChanges();
}

Ce code crée une nouvelle instance de Customer et l’ajoute à la collection Customers. La méthode SaveChanges enregistre le nouveau client dans la base de données MongoDB.

Opération de lecture

Pour lire des documents depuis la collection MongoDB, vous pouvez utiliser des requêtes LINQ sur le DbSet. Voici un exemple de récupération de tous les clients :

using (var context = new MyDbContext(options))
{
    var customers = context.Customers.ToList();
    foreach (var customer in customers)
    {
        Console.WriteLine($"Customer: {customer.Name}, Order: {customer.Order}"); 
    }
}

Ce code récupère tous les clients de la collection Customers et affiche leurs détails.

Opération d’update

Pour mettre à jour un document existant, vous le récupérez, modifiez ses propriétés et appelez SaveChanges. Voici un exemple de mise à jour d’une commande de client :

using (var context = new MyDbContext(options))
{
    var customer = context.Customers.FirstOrDefault(c => c.Name == "Beau Carnes"); 
    if (customer != null)
    {
        customer.Order = "Smartphone";
        context.SaveChanges();
    }
}

Ce code recherche le client nommé « Beau Carnes » et met à jour sa commande en la changeant en « Smartphone ».

Opération de suppression

Pour supprimer un document, vous le récupérez, le retirez du DbSet et appelez SaveChanges. Voici un exemple de suppression de client :

using (var context = new MyDbContext(options))
{
    var customer = context.Customers.FirstOrDefault(c => c.Name == "Beau Carnes"); 
    if (customer != null)
    {
        context.Customers.Remove(customer);
        context.SaveChanges();
    }
}

Ce code recherche le client nommé « Beau Carnes » et le supprime de la collection Customers.

Gestion des modifications

Les capacités de suivi des modifications d’EF Core sont pleinement prises en charge, ce qui permet des mises à jour des documents efficientes. Lorsque vous modifiez une entité et appelez SaveChanges, EF Core générera les commandes MongoDB nécessaires pour mettre à jour seulement les champs modifiés.

En utilisant le fournisseur MongoDB EF, vous pouvez intégrer seamlessement le modèle documentaire flexible de MongoDB avec les capacités robustes d’ORM d’EF Core, fournissant un outillage puissant pour les développeurs .NET pour construire des applications modernes.

Tutoriel

Maintenant, essayons de mettre tout cela ensemble et de créer un système de réservation de restaurants.

Prérequis

Pour suivre ce tutoriel, vous aurez besoin de quelques choses :

Créer le projet

ASP.NET Core est un framework web très flexible, qui permet de générer différents types d’applications web avec des différences mineures en termes de UI ou de structure. Pour ce tutoriel, nous allons créer un projet MVC qui utilisera des fichiers statiques et des contrôleurs. Il existe d’autres types de front-end que vous pourriez utiliser, tels que React, mais MVC avec des vues .cshtml est le plus communément utilisé. Pour créer le projet, nous allons utiliser le .NET CLI :

dotnet new mvc -o RestRes

Parce que nous avons utilisé le CLI, ce qui est plus simple, il ne crée que le fichier csproj et non pas le fichier de solution qui permet d’ouvrir le projet dans Visual Studio, donc nous allons corriger cela.

cd RestRes
dotnet new sln
dotnet sln .\RestRes.sln add .\RestRes.csproj

Ajouter les paquets NuGet

Maintenant que nous avons créé le nouveau projet, nous voudrons enregistrer et ajouter les paquets NuGet requis. Soit en utilisant le gestionnaire de paquets NuGet ou en utilisant la commande du .NET CLI ci-dessous, ajoutez le paquet MongoDB MongoDB.EntityFrameworkCore.

dotnet add package MongoDB.EntityFrameworkCore

Créer les modèles

Avant de commencer à implémenter les nouveaux paquets que nous venons d’ajouter, nous devons créer les modèles qui représentent les entités que nous souhaitons avoir dans notre système de réservation de restaurants, qui seront naturellement stockées en tant que documents dans MongoDB Atlas. Dans les sous-paragraphes suivants, nous créerons les modèles suivants :

  • Restaurant

  • Reservation

  • MongoDBSettings

Restaurant

Tout d’abord, nous devons créer notre modèle de restaurant qui représentera les restaurants disponibles pour être réservés dans notre système.

  1. Créez un nouveau fichier dans le dossier Models appelé Restaurant.cs.

  2. Ajoutez le code suivant :

using MongoDB.Bson;
using MongoDB.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;


namespace RestRes.Models
{
    [Collection("restaurants")]    
    public class Restaurant
    {

        public ObjectId Id { get; set; }

        [Required(ErrorMessage = "You must provide a name")]
        [Display(Name = "Name")]
        public string? name { get; set; }


        [Required(ErrorMessage = "You must add a cuisine type")]
        [Display(Name = "Cuisine")]
        public string? cuisine { get; set; }


        [Required(ErrorMessage = "You must add the borough of the restaurant")]
        public string? borough { get; set; }

    }
}

L’attribut de collection avant la classe indique à l’application quelle collection du base de données nous utilisons. Cela nous permet d’avoir des noms ou des capitalisations différents entre notre classe et notre collection si nous le souhaitons.

Reservation

Nous avons également besoin de créer une classe de réservation pour représenter toutes les réservations que nous prenons dans notre système.

  1. Créez un nouveau fichier dans le dossier Models appelé Reservation.cs.

  2. Ajoutez le code suivant à celui-ci :

using MongoDB.Bson;
using MongoDB.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;


namespace RestRes.Models
{
    [Collection("reservations")]
    public class Reservation
    {
        public ObjectId Id { get; set; }


        public ObjectId RestaurantId { get; set; }


        public string? RestaurantName { get; set; }

        [Required(ErrorMessage = "The date and time is required to make this reservation")]
        [Display(Name = "Date")]
        public DateTime date { get; set; }

    }
}

MongoDBSettings

Bien que ce ne soit pas un document dans notre base de données, nous avons besoin d’une classe modèle pour stocker nos paramètres liés à MongoDB afin qu’ils puissent être utilisés dans toute l’application.

  1. Créer un autre fichier dans le dossier Models nommé MongoDBSettings.cs.

  2. Ajouter le code suivant :

namespace RestRes.Models
{
  public class MongoDBSettings
  {
      public string AtlasURI { get; set; }
      public string DatabaseName { get; set; }
  }
}

Configuration de EF Core

C’est la partie passionnante. Nous allons commencer à implémenter EF Core et profiter du nouveau fournisseur MongoDB. Si vous êtes habitué à travailler avec EF Core, certaines parties de cela vous seront familières.

RestaurantReservationDbContext

  1. Créer un dossier Services, puis créer un fichier nommé RestaurantReservationDbContext.cs.

  2. Remplacer le code à l’intérieur du namespace par le suivant :

using Microsoft.EntityFrameworkCore;
using RestRes.Models;

namespace RestRes.Services
{
    public class RestaurantReservationDbContext : DbContext
    {
        public DbSet<Restaurant> Restaurants { get; init; }      


        public DbSet<Reservation> Reservations { get; init; }


        public RestaurantReservationDbContext(DbContextOptions options)
        : base(options)
        {
        }


        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);


            modelBuilder.Entity<Restaurant>();
            modelBuilder.Entity<Reservation>();
        }
    }
}

Si vous êtes habitué à EF Core, cela ressemblera à ce que vous connaissez. La classe hérite de DbContext et nous créons des propriétés DbSet qui stockent les modèles qui seront également présents dans la base de données. Nous aussi overrideons la méthode OnModelCreating. Vous pourriez remarquer que contrairement à l’utilisation de SQL Server, nous n’appelons pas .ToTable(). Nous pourrions appeler ToCollection à la place, mais cela n’est pas nécessaire ici car nous spécifions la collection en utilisant des attributs sur les classes.

Ajouter la chaîne de connexion et les détails de la base de données à appsettings

Précédemment, nous avons créé un modèle MongoDBSettings, et maintenant, nous devons ajouter les valeurs auxquelles les propriétés se mappent dans notre appsettings.

  1. Dans les fichiers appsettings.json et appsettings.Development.json, ajoutez la section suivante :

      "MongoDBSettings": {
        "AtlasURI": "mongodb+srv://<username>:<password>@<url>",
        "DatabaseName": "restaurants"
      }
    
  2. Remplacez l’URI Atlas par votre propre chaîne de connexion d’Atlas.

Mise à jour du fichier program.cs

Maintenant que nous avons configuré nos modèles et notre DbContext, il est temps d’ajouter les uns et les autres à notre fichier program.cs.

Après la ligne existante builder.Services.AddControllersWithViews();, ajoutez le code suivant :

var mongoDBSettings = builder.Configuration.GetSection("MongoDBSettings").Get<MongoDBSettings>();
builder.Services.Configure<MongoDBSettings>(builder.Configuration.GetSection("MongoDBSettings"));

builder.Services.AddDbContext<RestaurantReservationDbContext>(options =>
options.UseMongoDB(mongoDBSettings.AtlasURI ?? "", mongoDBSettings.DatabaseName ?? ""));

Création des services

Maintenant, il est temps d’ajouter les services que nous utiliserons pour communiquer avec la base de données via le RestaurantBookingDbContext que nous avons créé. Pour chaque service, nous créerons une interface et la classe qui l’implémente.

IRestaurantService et RestaurantService

La première interface et service que nous implémenterons est utilisée pour effectuer les opérations CRUD sur la collection des restaurants. Cela s’appelle le patron de référentiel. Vous pouvez voir les gens interagir directement avec le DbContext. Cependant, la plupart des gens utilisent ce patron, ce qui est pourquoi nous l’inclions ici.

  1. Si vous n’avez pas déjà fait, créez un dossier Services pour stocker nos nouvelles classes.

  2. Créez une interface IRestaurantService et ajoutez le code suivant pour les méthodes que nous implémenterons :

using MongoDB.Bson;
using RestRes.Models;

namespace RestRes.Services
{
    public interface IRestaurantService
    {
        IEnumerable<Restaurant> GetAllRestaurants();
        Restaurant? GetRestaurantById(ObjectId id);

        void AddRestaurant(Restaurant newRestaurant);

        void EditRestaurant(Restaurant updatedRestaurant);

        void DeleteRestaurant(Restaurant restaurantToDelete);
    }
}
  1. Créez un fichier de classe RestaurantService.

  2. Mettez à jour la déclaration de la classe RestaurantService pour qu’elle implémente l’interface IRestaurantService que nous venons de créer :

using Microsoft.EntityFrameworkCore;
using MongoDB.Bson;
using MongoDB.Driver;
using RestRes.Models;

namespace RestRes.Services
{
  public class RestaurantService : IRestaurantService
  {
    private readonly RestaurantReservationDbContext _restaurantDbContext;
    public RestaurantService(RestaurantReservationDbContext restaurantDbContext)
    {
        _restaurantDbContext = restaurantDbContext;
    }

    public void AddRestaurant(Restaurant restaurant)
    {
      _restaurantDbContext.Restaurants.Add(restaurant);

      _restaurantDbContext.ChangeTracker.DetectChanges();
      Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

      _restaurantDbContext.SaveChanges();
    }

    public void DeleteRestaurant(Restaurant restaurant)
    {
      var restaurantToDelete = _restaurantDbContext.Restaurants.Where(c => c.Id == restaurant.Id).FirstOrDefault();

      if(restaurantToDelete != null) {
          _restaurantDbContext.Restaurants.Remove(restaurantToDelete);
        _restaurantDbContext.ChangeTracker.DetectChanges();
          Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);
          _restaurantDbContext.SaveChanges();
          }
        else {
            throw new ArgumentException("The restaurant to delete cannot be found.");
        }
    }

    public void EditRestaurant(Restaurant restaurant)
    {
          var restaurantToUpdate = _restaurantDbContext.Restaurants.FirstOrDefault(c => c.Id == restaurant.Id);

        if(restaurantToUpdate != null)
        {                
            restaurantToUpdate.name = restaurant.name;
            restaurantToUpdate.cuisine = restaurant.cuisine;
            restaurantToUpdate.borough = restaurant.borough;

            _restaurantDbContext.Restaurants.Update(restaurantToUpdate);

            _restaurantDbContext.ChangeTracker.DetectChanges();
            Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

            _restaurantDbContext.SaveChanges();

        }
      else
        {
            throw new ArgumentException("The restaurant to update cannot be found. ");
        }
    }        

    public IEnumerable<Restaurant> GetAllRestaurants()
    {
      return _restaurantDbContext.Restaurants.OrderByDescending(c => c.Id).Take(20).AsNoTracking().AsEnumerable<Restaurant>();
    }

    public Restaurant? GetRestaurantById(ObjectId id)
    {
      return _restaurantDbContext.Restaurants.FirstOrDefault(c  => c.Id == id);
    }
  }

}

IReservationService et ReservationService

Ensuite, nous avons notre IReservationService et ReservationService.

Créez l’interface IReservationService et ajoutez les méthodes suivantes :

using MongoDB.Bson;
using RestRes.Models;

namespace RestRes.Services
{
    public interface IReservationService
    {
        IEnumerable<Reservation> GetAllReservations();
        Reservation? GetReservationById(ObjectId id);

        void AddReservation(Reservation newReservation);

        void EditReservation(Reservation updatedReservation);

        void DeleteReservation(Reservation reservationToDelete);
    }
}

Créez la classe ReservationService et remplacez votre classe avec le code suivant qui implémente toutes les méthodes :

using Microsoft.EntityFrameworkCore;
using MongoDB.Bson;
using RestRes.Models;

namespace RestRes.Services
{
    public class ReservationService : IReservationService
    {
        private readonly RestaurantReservationDbContext _restaurantDbContext;

        public ReservationService(RestaurantReservationDbContext restaurantDbContext)
        {
            _restaurantDbContext = restaurantDbContext;
        }
        public void AddReservation(Reservation newReservation)
        {
            var bookedRestaurant = _restaurantDbContext.Restaurants.FirstOrDefault(c => c.Id == newReservation.RestaurantId);
            if (bookedRestaurant == null)
            {
                throw new ArgumentException("The restaurant to be reserved cannot be found.");
            }

            newReservation.RestaurantName = bookedRestaurant.name;

            _restaurantDbContext.Reservations.Add(newReservation);

            _restaurantDbContext.ChangeTracker.DetectChanges();
            Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

            _restaurantDbContext.SaveChanges();
        }

        public void DeleteReservation(Reservation reservation)
        {
            var reservationToDelete = _restaurantDbContext.Reservations.FirstOrDefault(b => b.Id == reservation.Id);

            if(reservationToDelete != null)
            {
                _restaurantDbContext.Reservations.Remove(reservationToDelete);

                _restaurantDbContext.ChangeTracker.DetectChanges();
                Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

                _restaurantDbContext.SaveChanges();
            }
            else
            {
                throw new ArgumentException("The reservation to delete cannot be found.");
            }
        }

        public void EditReservation(Reservation updatedReservation)
        {
           var reservationToUpdate = _restaurantDbContext.Reservations.FirstOrDefault(b => b.Id == updatedReservation.Id);


            if (reservationToUpdate != null)
            {               
                reservationToUpdate.date = updatedReservation.date;

                _restaurantDbContext.Reservations.Update(reservationToUpdate);

                _restaurantDbContext.ChangeTracker.DetectChanges();
                _restaurantDbContext.SaveChanges();

                Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);
            }  
            else 
            { 
                throw new ArgumentException("Reservation to be updated cannot be found");
            }

        }

        public IEnumerable<Reservation> GetAllReservations()
        {
            return _restaurantDbContext.Reservations.OrderBy(b => b.date).Take(20).AsNoTracking().AsEnumerable<Reservation>();
        }

        public Reservation? GetReservationById(ObjectId id)
        {
            return _restaurantDbContext.Reservations.AsNoTracking().FirstOrDefault(b => b.Id == id);
        }

    }
}

Ce code est très similaire au code de la classe RestaurantService, mais pour les réservations.

Ajoutez-les au Injection de dépendances

La dernière étape pour les services est d’ajouter les uns aux autres dans le container d’injection de dépendances.

Dans le fichier Program.cs, ajoutez le code suivant après le code que vous avez ajouté plus tôt :

builder.Services.AddScoped<IRestaurantService, RestaurantService>();
builder.Services.AddScoped<IReservationService, ReservationService>();

Créer les modèles de vue

Avant d’implémenter l’interface utilisateur, nous devons ajouter les modèles de vue qui agiront comme un messageur entre notre interface utilisateur et son interface arrière-plan où nécessaire. Même si notre application est assez simple, implémenter le modèle de vue est toujours une bonne pratique car il aide à désynchroniser les parties de l’application.

RestaurantListViewModel

Le premier que nous ajouterons est le RestaurantListViewModel. Il sera utilisé comme modèle dans notre page Razor ultérieure pour lister les restaurants de notre base de données.

  1. Créez un nouveau dossier au root du projet nommé ViewModels.

  2. Ajoutez un nouveau fichier appelé RestaurantListViewModel.cs.

  3. Ajoutez le code suivant :

using RestRes.Models;

namespace RestRes.ViewModels
{
    public class RestaurantListViewModel
    {        
        public IEnumerable<Restaurant>? Restaurants { get; set; }
    }
}

RestaurantAddViewModel

Nous voulons également un modèle de vue qui peut être utilisé par la vue Add que nous ajouterons ultérieurement.

  1. Dans le dossier ViewModels, créez un nouveau fichier nommé RestaurantAddViewMode.cs.

  2. Ajouter :

using RestRes.Models;

namespace RestRes.ViewModels
{
    public class RestaurantAddViewModel
    {
        public Restaurant? Restaurant { get; set; } 
    }
}

ReservationListViewModel

Maintenant, nous voulons faire quelque chose de très similaire pour les réservations, en commençant par ReservationListViewModel.

  1. Créez un nouveau fichier dans le dossier ViewModels nommé ReservationListViewModel.cs.

  2. Ajouter :

using RestRes.Models;

namespace RestRes.ViewModels
{
    public class ReservationListViewModel
    {
        public IEnumerable<Reservation>? Reservations { get; set; }
    }
}

ReservationAddViewModel

Enfin, nous avons notre ReservationAddViewModel.

Créer le fichier et ajoutez ce code :

using RestRes.Models;

namespace RestRes.ViewModels
{
    public class ReservationAddViewModel
    {
        public Reservation? Reservation { get; set; }
    }
}

Ajout à _ViewImports

Plus tard, nous ajouterons des références à nos modèles et à nos vues dans les vues. Afin que l’application sache ce que ce sont, nous devons ajouter des références à ces derniers dans le fichier _ViewImports.cshtml situé dans le dossier Views.

Il y a déjà certaines références dans là, y compris les TagHelpers, donc nous voulons ajouter des références à nos dossiers .Models et .ViewModels. Donc le haut du fichier devrait ressembler à ceci :

@using RestRes
@using RestRes.Models
@using RestRes.ViewModels

Création des contrôleurs

Maintenant que nous avons l’implémentation backend et les vues auxquelles nous nous référerons, nous pouvons commencer à travailler vers l’avant-plan. Nous créerons deux contrôleurs : un pour le Restaurant et un pour la Réservation.

RestaurantController

Le premier contrôleur que nous ajouterons est pour le restaurant.

  1. Dans le dossier Controllers existant, ajouter un nouveau fichier de contrôleur appelé RestaurantController.cs. Si vous utilisez Visual Studio, utilisez le modèle de contrôleur MVC – Contrôleur vide.

  2. Ajoutez ce code :

using Microsoft.AspNetCore.Mvc;
using MongoDB.Bson;
using RestRes.Models;
using RestRes.Services;
using RestRes.ViewModels;

namespace RestRes.Controllers
{
    public class RestaurantController : Controller
    {
        private readonly IRestaurantService _RestaurantService;

        public RestaurantController(IRestaurantService RestaurantService)
        {
            _RestaurantService = RestaurantService;
        }
        public IActionResult Index()
        {
            RestaurantListViewModel viewModel = new()
            {
                Restaurants = _RestaurantService.GetAllRestaurants(),
            };
            return View(viewModel);
        }

        public IActionResult Add()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Add(RestaurantAddViewModel restaurantAddViewModel)
        {
            if(ModelState.IsValid)
            {
                Restaurant newRestaurant = new()
                {
                    name = restaurantAddViewModel.Restaurant.name,
                    borough = restaurantAddViewModel.Restaurant.borough,
                    cuisine = restaurantAddViewModel.Restaurant.cuisine
                };

                _RestaurantService.AddRestaurant(newRestaurant);
                return RedirectToAction("Index");
            }

            return View(restaurantAddViewModel);         
        }

        public IActionResult Edit(ObjectId id)
        {
            if(id == null || id == ObjectId.Empty)
            {
                return NotFound();
            }

            var selectedRestaurant = _RestaurantService.GetRestaurantById(id);
            return View(selectedRestaurant);
        }

        [HttpPost]
        public IActionResult Edit(Restaurant restaurant)
        {
            try
            {
                if(ModelState.IsValid)
                {
                    _RestaurantService.EditRestaurant(restaurant);
                    return RedirectToAction("Index");
                }
                else
                {
                    return BadRequest();
                }
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", $"Updating the restaurant failed, please try again! Error: {ex.Message}");
            }

            return View(restaurant);
        }

        public IActionResult Delete(ObjectId id) {
            if (id == null || id == ObjectId.Empty)
            {
                return NotFound();
            }

            var selectedRestaurant = _RestaurantService.GetRestaurantById(id);
            return View(selectedRestaurant);
        }

        [HttpPost]
        public IActionResult Delete(Restaurant restaurant)
        {
            if (restaurant.Id == ObjectId.Empty)
            {
                ViewData["ErrorMessage"] = "Deleting the restaurant failed, invalid ID!";
                return View();
            }

            try
            {
                _RestaurantService.DeleteRestaurant(restaurant);
                TempData["RestaurantDeleted"] = "Restaurant deleted successfully!";

                return RedirectToAction("Index");
            }
            catch (Exception ex)
            {
                ViewData["ErrorMessage"] = $"Deleting the restaurant failed, please try again! Error: {ex.Message}";
            }

            var selectedRestaurant = _RestaurantService.GetRestaurantById(restaurant.Id);
            return View(selectedRestaurant);
        }        
    }
}

ReservationController

Maintenant, pour le contrôleur de réservation. C’est très similaire au RestaurantController mais il a une référence à la fois au restaurant et au service de réservation car nous avons besoin d’associer un restaurant à une réservation. C’est parce que pour le moment, le fournisseur EF Core ne supporte pas les relations entre les entités, donc nous pouvons lier les entités de manière différente.

  1. Créer un autre fichier de contrôleur MVC vide appelé ReservationController.cs.

  2. Collez le code suivant :

using Microsoft.AspNetCore.Mvc;
using MongoDB.Bson;
using RestRes.Models;
using RestRes.Services;
using RestRes.ViewModels;

namespace RestRes.Controllers
{
    public class ReservationController : Controller
    {
        private readonly IReservationService _ReservationService;
        private readonly IRestaurantService _RestaurantService;        

        public ReservationController(IReservationService ReservationService, IRestaurantService RestaurantService)
        {
            _ReservationService = ReservationService;
            _RestaurantService = RestaurantService;
        }

        public IActionResult Index()
        {
            ReservationListViewModel viewModel = new ReservationListViewModel()
            {
                Reservations = _ReservationService.GetAllReservations()
            };
            return View(viewModel);
        }

        public IActionResult Add(ObjectId restaurantId)
        {
            var selectedRestaurant = _RestaurantService.GetRestaurantById(restaurantId);

            ReservationAddViewModel reservationAddViewModel = new ReservationAddViewModel();

            reservationAddViewModel.Reservation = new Reservation();
            reservationAddViewModel.Reservation.RestaurantId = selectedRestaurant.Id;
            reservationAddViewModel.Reservation.RestaurantName = selectedRestaurant.name;
            reservationAddViewModel.Reservation.date = DateTime.UtcNow;

            return View(reservationAddViewModel);
        }

        [HttpPost]
        public IActionResult Add(ReservationAddViewModel reservationAddViewModel)
        {
                Reservation newReservation = new()
                {
                    RestaurantId = reservationAddViewModel.Reservation.RestaurantId,                   
                    date = reservationAddViewModel.Reservation.date,
                };

                _ReservationService.AddReservation(newReservation);
                return RedirectToAction("Index");   
        }

        public IActionResult Edit(string Id)
        {
            if(Id == null || string.IsNullOrEmpty(Id))
            {
                return NotFound();
            }

            var selectedReservation = _ReservationService.GetReservationById(new ObjectId(Id));
            return View(selectedReservation);
        }

        [HttpPost]
        public IActionResult Edit(Reservation reservation)
        {
            try
            {
                var existingReservation = _ReservationService.GetReservationById(reservation.Id);
                if (existingReservation != null)
                {
                    _ReservationService.EditReservation(reservation);
                    return RedirectToAction("Index");
                }
                else
                {
                    ModelState.AddModelError("", $"Reservation with ID {reservation.Id} does not exist!");
                }
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", $"Updating the reservation failed, please try again! Error: {ex.Message}");
            }

            return View(reservation);
        }

        public IActionResult Delete(string Id)
        {
            if (Id == null || string.IsNullOrEmpty(Id))
            {
                return NotFound();
            }

            var selectedReservation = _ReservationService.GetReservationById(new ObjectId(Id));
            return View(selectedReservation);
        }

        [HttpPost]
        public IActionResult Delete(Reservation reservation)
        {
            if(reservation.Id == null)
            {
                ViewData["ErrorMessage"] = "Deleting the reservation failed, invalid ID!";
                return View();
            }

            try
            {
                _ReservationService.DeleteReservation(reservation);
                TempData["ReservationDeleted"] = "Reservation deleted successfully";

                return RedirectToAction("Index");
            }
            catch (Exception ex)
            {
                ViewData["ErrorMessage"] = $"Deleting the reservation failed, please try again! Error: {ex.Message}";
            }

            var selectedRestaurant = _ReservationService.GetReservationById(reservation.Id);
            return View(selectedRestaurant);
        }
    }
}

Création des vues

Maintenant que nous avons préparé le back-end et les contrôleurs avec les points de terminaison pour notre système de réservation de restaurants, il est temps d’implémenter les vues. Cela se fera en utilisant des pages Razor. Vous verrez également des références à des classes de Bootstrap car c’est le framework CSS qui accompagne les applications MVC par défaut. Nous fournirons des vues pour les opérations CRUD pour les listes et les réservations.

Listing des restaurants

Tout d’abord, nous fournirons une vue qui sera mapée à la racine de /Restaurant, qui se fera selon la convention Regarder la méthode Index que nous avons implémentée.

ASP.NET Core MVC utilise un modèle de convention selon lequel vous nommez le fichier .cshtml le nom de l’extrémité/méthode qu’il utilise et il se trouve dans un dossier nommé d’après son contrôleur.

  1. Dans le dossier Views, créez un nouveau sous-dossier appelé Restaurant.

  2. Dans ce dossier Restaurant, ajoutez une nouvelle vue en créant un fichier appelé Index.cshtml. Si vous utilisez les modèles disponibles, vous souhaitez une Vue Razor – Vide. Nommez la vue Index.

  3. Ajoutez ce code :

@model RestaurantListViewModel

@if (TempData["RestaurantDeleted"] != null)
{
    <p class="text-success">@TempData["RestaurantDeleted"]</p>
}


@if (!Model.Restaurants.Any())
{
    <p>No results</p>
}
else
{
    <table class="table table-condensed table-bordered">
        <tr>
            <th>
                Name
            </th>
            <th>
                Cuisine
            </th>
            <th>
                Borough
            </th>            
            <th>
                Actions
            </th>
        </tr>

        @foreach (var restaurant in Model.Restaurants)
        {
            <tr>
                <td>@restaurant.name</td>
                <td>@restaurant.cuisine</td>
                <td>@restaurant.borough</td>                
                <td>
                    <a asp-action="Edit" asp-route-id="@restaurant.Id.ToString()">Edit</a>
                    <a asp-action="Delete" asp-route-id="@restaurant.Id.ToString()">Delete</a>
                    <a asp-controller="Reservation" asp-action="Add" asp-route-restaurantId="@restaurant.Id.ToString()">Reserve</a>
                </td>
            </tr>
        }

    </table>
}

<p>
    <a class="btn btn-primary" asp-action="Add">Add new restaurant</a>
</p>

Maintenant, modifions la route par défaut de Home vers /Restaurant.

Dans Program.cs, à l’intérieur de app.MapControllerRoute, remplacez la ligne du modèle par ce qui suit :

pattern: "{controller=Restaurant}/{action=Index}/{id?}");

Si nous exécutions cela maintenant, les boutons conduiraient à des 404 car nous n’avons pas encore implémenté ceux-ci. So let’s faites-le maintenant.

Ajouter des restaurants

Nous commencerons par le formulaire pour ajouter de nouveaux restaurants.

  1. Ajoutez une nouvelle vue vide Razor dans le sous-dossier Restaurant appelé Add.cshtml.

  2. Ajoutez le code suivant :

@model RestaurantAddViewModel

<h2>Create a new restaurant</h2>
<hr />

@if (ViewData["ErrorMessage"] != null)
{
    <p class="text-danger">@ViewData["ErrorMessage"]</p>
}

<form method="post" asp-controller="Restaurant" asp-action="Add">
    <div asp-validation-summary="All" class="text-danger"></div>

    <div class="mb-3">
        <label asp-for="Restaurant.name" class="form-label"></label>
        <input asp-for="Restaurant.name" class="form-control" />
        <span asp-validation-for="Restaurant.name" class="text-danger"></span>
    </div>

    <div class="mb-3">
        <label asp-for="Restaurant.cuisine" class="form-label"></label>
        <input asp-for="Restaurant.cuisine" class="form-control" />
        <span asp-validation-for="Restaurant.cuisine" class="text-danger"></span>
    </div>

      <div class="mb-3">
        <label asp-for="Restaurant.borough" class="form-label">Borough</label>
        <input asp-for="Restaurant.borough" class="form-control" />
        <span asp-validation-for="Restaurant.borough" class="text-danger"></span>
    </div>

    <input type="submit" value="Add restaurant" class="btn btn-primary" />
</form>

<div>
    <a asp-controller="Restaurant" asp-action="Index">Back to list</a>
</div>

Édition des restaurants

Le code de la page Edition est presque identique à celui de l’ajout, mais il utilise le restaurant comme modèle car il utilisera le restaurant passé pour pré-remplir le formulaire d’édition.

  1. Ajoutez une autre vue à l’intérieur du dossier Restaurant appelé Edit.cshtml.

  2. Ajoutez le code suivant :

@model Restaurant

<h2>Update @Model.name</h2>
<hr />

<form method="post" asp-controller="Restaurant" asp-action="Edit">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="Id" />

    <div class="mb-3">
        <label asp-for="name" class="form-label">Name</label>
        <input asp-for="name" class="form-control" />
        <span asp-validation-for="name" class="text-danger"/>
    </div>
    <div class="mb-3">
        <label asp-for="cuisine" class="form-label"></label>
        <input asp-for="cuisine" class="form-control" />
        <span asp-validation-for="cuisine" class="text-danger"/>
    </div>
    <div class="mb-3">
        <label asp-for="borough" class="form-label">Borough</label>
        <input asp-for="borough" class="form-control" />
        <span asp-validation-for="borough" class="text-danger"/>
    </div>
    <input type="submit" value="Update restaurant" class="btn btn-primary" />
</form>
<div>
    <a asp-controller="Restaurant" asp-action="Index">Back to list</a>
</div>

Suppression des restaurants

La dernière page que nous avons besoin d’implémenter est la page appelée lorsque le bouton Supprimer est cliqué.

  1. Créer une nouvelle vue vide appelée Delete.cshtml.

  2. Ajoutez le code suivant :

@model Restaurant

<h2>Deleting @Model.name</h2>
<hr />

@if(ViewData["ErrorMessage"] != null)
{
    <p class="text-danger">@ViewData["ErrorMessage"]</p>
}

<div>
    <dl class="row">
        <dt class="col-sm-4">
            <label asp-for="name">Name</label>
        </dt>
        <dd class="col-sm-10">
            @Model?.name
        </dd>
        <dt class="col-sm-2">
            <label asp-for="cuisine"></label>
        </dt>
        <dd class="col-sm-10">
            @Model?.cuisine
        </dd>
        <dt class="col-sm-2">
            <label asp-for="borough">Borough</label>
        </dt>
        <dd class="col-sm-10">
            @Model?.borough
        </dd>

    </dl>
</div>

<form method="post" asp-action="Delete">
    <input type="hidden" asp-for="Id" />
    <input type="submit" value="Delete restaurant" class="btn btn-danger" onclick="javascript: return confirm('Are you sure you want to delete this restaurant?');" />
</form>

<div>
    <a asp-controller="Restaurant" asp-action="Index">Back to list</a>
</div>

Listage des réservations

Nous avons ajouté les vues pour les restaurants, maintenant nous ajouterons les vues pour les réservations, en commençant par la listage de toutes les réservations existantes.

  1. Créer un nouveau dossier à l’intérieur du dossier Views appelé Reservation.

  2. Créer un nouvel fichier de vue vide appelé Index.cshtml.

  3. Ajoutez le code suivant pour afficher les réservations, si elles existent :

@model ReservationListViewModel

@if (TempData["ReservationDeleted"] != null)
{
    <p class="text-success">@TempData["ReservationDeleted"]</p>
}

@if (!Model.Reservations.Any())
{
    <p>No results</p>
}

else
{    
    <table class="table table-condensed table-bordered">
        <tr>
            <th>
                Booked Restaurant
            </th>
            <th>
                Date and Time
            </th>
            <th>
                Actions
            </th>
        </tr>

        @foreach(var reservation in Model.Reservations)
        {
            <tr>
                <td>@reservation.RestaurantName</td>
                <td>@reservation.date.ToLocalTime()</td>
                <td>
                    <a asp-action="Edit" asp-route-id="@reservation.Id.ToString()">Edit</a>
                    <a asp-action="Delete" asp-route-id="@reservation.Id.ToString()">Delete</a>
                </td>
            </tr>
        }

    </table>   

}

Ajout de réservations

Ajout de réservations est le prochain pas.

  1. Créer une vue vide nommée Add.cshtml.

  2. Ajouter le code suivant :

@model ReservationAddViewModel


@if (ViewData["ErrorMessage"] != null)
{
    <p class="text-danger">@ViewData["ErrorMessage"]</p>
}

<form method="post" asp-controller="Reservation" asp-action="Add">
    <div asp-validation-summary="All" class="text-danger"></div>
    <input type="hidden" asp-for="Reservation.Id" />
    <input type="hidden" asp-for="Reservation.RestaurantId" />

    <div class="mb-3">
        <label asp-for="Reservation.date" class="form-label"></label>
        <input asp-for="Reservation.date" type="datetime-local" class="form-control" value="@DateTime.Now.ToString("yyyy-MM-ddTHH:mm")" />
        <span asp-validation-for="Reservation.date" class="text-danger"></span>
    </div>

    <input type="submit" value="Reserve table" class="btn btn-primary" />
</form>

Modification de réservations

Modification de réservations est le prochain pas.

  1. Créer une vue vide nommée Edit.cshtml.

  2. Ajouter le code suivant :

@model Reservation

<h2>Editing reservation for @Model.RestaurantName on @Model.date.ToLocalTime()</h2>
<hr />

<form method="post" asp-controller="Reservation" asp-action="Edit">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="Id" />

    <div class="mb-3">
        <label asp-for="date" class="form-label"></label>
        <input asp-for="date" value="@Model.date.ToLocalTime().ToString("yyyy-MM-ddTHH:mm")" class="form-control" />
        <span asp-validation-for="date" class="text-danger" />
    </div>
    <input type="submit" value="Update reservation" class="btn btn-primary" />
</form>
<div>
    <a asp-controller="Reservation" asp-action="Index">Back to reservations</a>
</div>

Suppression de réservations

Suppression de réservations est le prochain pas.

  1. Créer une vue vide nommée Delete.cshtml.

  2. Ajouter le code suivant :

@model Reservation

<h2>Delete reservation</h2>
<hr />

@if (ViewData["ErrorMessage"] != null)
{
    <p class="text-danger">@ViewData["ErrorMessage"]</p>
}

<div>
    <dl class="row">
        <dt class="col-sm-2">
            <label asp-for="RestaurantName">Name</label>
        </dt>
        <dd class="col-sm-10">
            @Model?.RestaurantName
        </dd>
        <dt class="col-sm-2">
            <label asp-for="date"></label>
        </dt>
        <dd class="col-sm-10">
            @Model?.date.ToLocalTime()
        </dd>
        </dl>
</div>

<form method="post" asp-action="Delete">
    <input type="hidden" asp-for="Id" />
    <input type="hidden" asp-for="RestaurantId" />
    <input type="submit" value="Delete reservation" class="btn btn-danger" onclick="javascript: return confirm('Are you sure you want to delete this reservation?');" />
</form>

<div>
    <a asp-controller="Reservation" asp-action="Index">Back to list</a>
</div>

Mise à jour de la NavBar

La dernière chose à ajouter est de mettre à jour la barre de navigation de l’application pour pouvoir facilement passer d’un restaurant à une réservation.

Allez au fichier situé à Views/Shared/_Layout.cshtml. Trouvez le div avec la classe navbar-collapse. Supprimez complètement cette section et ajoutez le code suivant :

<div class="collapse navbar-collapse justify-content-between">
    <ul class="navbar-nav flex-grow-1">
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-controller="Restaurant" asp-action="Index">Restaurants</a>
        </li>
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-controller="Reservation" asp-action="Index">Reservations</a>
        </li>
    </ul>
</div>

Testons notre application

Nous avons maintenant une application fonctionnelle qui utilise le nouveau fournisseur MongoDB pour EF Core. Il est maintenant temps de la tester et de visiter nos points de terminaison pour s’assurer que tout fonctionne.

Dans le terminal, exécutez la commande suivante :

dotnet run

essayez de modifier les restaurants et d’ajouter des réservations. Vous pourrez ensuite naviguer vers la page de la base de données MongoDB Atlas et constater que vos modifications sont reflétées dans la base de données.

Opérations avancées MongoDB : Recherche Atlas et Recherche vectorielle

Le fournisseur EF Core est construit sur le pilote MongoDB C#. Comme nous avons déjà accès au MongoClient lors de la création du DbContext, cela nous permet de réaliser des opérations avancées MongoDB telles que la Recherche Atlas et la Recherche vectorielle. Ces fonctionnalités améliorent les capacités de votre application en permettant des fonctions de recherche puissantes tout en exploitant leurs ressources dans le contexte familier d’EF Core.

La Recherche Atlas est un moteur de recherche de texte intégral fourni par MongoDB Atlas. Elle permet de lancer des requêtes de recherche sophistiquées sur vos données MongoDB. Avec Atlas Search, vous pouvez implémenter des fonctions telles que la complétion automatique, la recherche segmentée et le tri basé sur la pertinence.

Pour utiliser la Recherche Atlas avec le fournisseur EF Core, suivez ces étapes :

  1. Configurer les indexes dans MongoDB Atlas:

    • Allez à votre cluster MongoDB Atlas.

    • Naviguez vers l’onglet « Recherche » et créez un nouvel index sur votre collection. Définissez les champs que vous souhaitez rendre recherchables.

  2. Définissez les champs recherchables dans vos modèles : Dans vos modèles C#, assurez-vous que les champs que vous souhaitez rechercher sont correctement définis. Voici un exemple de définition d’un modèle de produit.

     public class Product
     {
         public ObjectId Id { get; set; }
         public string Name { get; set; }
         public string Description { get; set; }
         public decimal Price { get; set; }
         public string Category { get; set; }
     }
    
  3. Exécution de Requêtes de Recherche : Utilisez les capacités du pilote MongoDB .NET pour effectuer des recherches de texte. Étant donné que EF Core ne supporte pas directement la syntaxe de recherche spécifique à MongoDB, vous devrez utiliser le pilote en conjonction avec EF Core. Voici un exemple :

     using MongoDB.Driver;
     using MongoDB.Driver.Linq;
    
     var client = new MongoClient("votre-string-de-connexion-mongodb");
     var database = client.GetDatabase("votre-nom-de-base-de-données");
     var collection = database.GetCollection<Product>("Products");
    
     var searchResult = collection.Aggregate()
         .Match(Builders<Product>.Filter.Text("terme-de-recherche"))
         .ToList();
    

Cet exemple montre comment effectuer une recherche de texte sur la collection Products. Le filtre Text permet de rechercher dans tous les champs indexés définis dans votre index de recherche Atlas Search.

La recherche vectorielle dans MongoDB est utilisée pour rechercher des documents sur la base de similarités entre vecteurs, ce qui est particulièrement utile pour les applications impliquant l’apprentissage automatique, les recommandations et le traitement naturel du langage. La recherche vectorielle vous permet de requêter des documents en utilisant des vecteurs représentant du texte, des images ou d’autres données de haut dimensionnel.

  1. Créer et stocker les vecteurs : Premièrement, veillez à ce que vos documents contiennent des vecteurs. Vous pourriez avoir besoin de préprocesser vos données pour générer ces vecteurs en utilisant des modèles d’apprentissage automatique.

  2. Indexer les vecteurs dans MongoDB Atlas : Créez un index spécial sur le champ vecteur dans MongoDB Atlas pour permettre des recherches de similarité de vecteurs efficaces.

  3. Réaliser des recherches vectorielles : Utilisez le pilote .NET de MongoDB pour interroger en fonction de la similarité vectorielle.

Intégration avec EF Core

Alors que le fournisseur EF Core de MongoDB simplifie les opérations CRUD, certaines fonctionnalités avancées telles que la recherche Atlas et la recherche vectorielle nécessitent une utilisation directe du pilote .NET de MongoDB. Cependant, vous pouvez toujours intégrer ces opérations au sein de votre application basée sur EF Core en utilisant le pilote pour les fonctionnalités de recherche et EF Core pour les autres tâches de gestion des données.

En combinant EF Core et les fonctionnalités avancées de MongoDB, vous pouvez construire des applications puissantes et flexibles qui exploitent le meilleur des deux mondes : les schémas d’accès aux données structurées d’EF Core et les puissantes capacités de recherche de MongoDB Atlas.