Entity Framework Core è un popolare ORM (Object-Relational Mapper) per applicazioni .NET, che consente agli sviluppatori di lavorare con database utilizzando oggetti .NET. Può essere utilizzato con molti tipi di database, incluso MongoDB.
In questo articolo, imparerete come puoi utilizzare Entity Framework Core con MongoDB. L’articolo copre i fondamenti, spiega i benefici e fornisce un tutorial passo-passo. Non importa se state appena iniziando con MongoDB o Entity Framework Core, o se state cercando di integrare questi tool nei vostri progetti .NET, questo guide vi aiuterà a colmare il gap tra database relazionali e NoSQL.
L’articolo inizia con una breve introduzione a MongoDB così come ad Entity Framework Core di Microsoft. Poi, copre come utilizzare il provider MongoDB per EF Core. Dopo aver attraversato i dettagli tecnici con alcuni esempi di base, create un progetto completo con MongoB e Entity Framework Core così da vedere come tutto funziona insieme. Il progetto userà i dati di esempio di MongoDB Atlas per creare un sistema di prenotazione per ristoranti.
C’è anche una versione video di questo articolo che puoi guardare sul canale YouTube di freeCodeCamp.org.
Introduzione a MongoDB
MongoDB è un popolare database NoSQL progettato per gestire grandi volumi di dati e fornire alta performance, scalabilità e flessibilità. A differenza dei database relazionali tradizionali, MongoDB memorizza i dati in documenti flessibili, simili a JSON. Questo approcio documentale consente la memorizzazione di strutture dati complesse in un modo più naturale e intuitivo.
In MongoDB, i dati sono memorizzati in collezioni, che sono simili a tabelle nei database relazionali ma senza uno schema fisso. Questo significa che puoi avere documenti con strutture differenti nella stessa collezione. questa flessibilità è una delle principali caratteristiche avanzate di MongoDB, specialmente quando si tratta di dati non strutturati o semi-strutturati.
Prendiamo un’occhiata ad un esempio di documento MongoDB. Immaginate di avere una collezione chiamata users
che memorizza informazioni riguardanti gli utenti di un’applicazione. Ecco come può sembrare un documento tipico:
{
"_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"]
}
In questo documento, abbiamo vari campi come name
, email
, age
, e address
. Il campo address
in sé è un documento incluso che contiene molti sotto-campi come street
, city
, state
, e zip
. Inoltre, il campo hobbies
è un array di stringhe.
Anche se questo sembra JSON, MongoDB memorizza i dati in un formato binario chiamato BSON (Binary JSON). BSON estende il modello JSON per fornire tipi di dati aggiuntivi, come interi, floating-point, date e dati binari. Questo formato binario è ottimizzato per la performance e la flessibilità, permettendo a MongoDB di memorizzare e recuperare i dati in maniera efficiente.
Un’altra caratteristica importante di MongoDB è la sua capacità di scalare orizzontalmente. Questo significa che puoi distribuire i tuoi dati su molti server, rendendo più facile la gestione di grandi set di dati e garantendo una elevata disponibilità. MongoDB supporta anche richieste ricche, indicizzazione e aggregazione, rendendolo una potente tool per un’ampia gamma di applicazioni.
Ad esempio, puoi eseguire una query per trovare tutti gli utenti che vivono in una specifica città:
db.users.find({ "address.city": "Anytown" })
Puoi trovare utenti che hanno un hobby specifico:
db.users.find({ "hobbies": "coding" })
MongoDB è ampiamente utilizzato in vari settori, dall’e-commerce e dalla gestione del contenuto alle analisi real-time e alle applicazioni Internet of Things (IoT). La sua flessibilità e la sua scalabilità lo rendono un’ottima scelta per applicazioni moderne che devono gestire dati diversi e dinamici.
Ora che abbiamo una base di conoscenza di base di cosa è MongoDB e perché è popolare, passiamo ad un’altra tool fondamentale nel nostro stack tecnologico: il Microsoft Entity Framework Core.
Introduzione a Microsoft Entity Framework Core
Entity Framework Core, spesso abbreviato in EF Core, è un moderno mapping oggetto-database per .NET. Permette agli sviluppatori di lavorare con una base dati utilizzando gli oggetti .NET, eliminando la necessità di scrivere la maggior parte del codice di accesso ai dati che gli sviluppatori di solito devono scrivere.
EF Core è una versione leggera, estensibile e multiplatforma della popolare tecnologia di accesso ai dati Entity Framework (EF). Supporta una varietà di motori di database, inclusi SQL Server, SQLite e MongoDB.
Un degli aspetti principali dell’utilizzo di EF Core è che consente agli sviluppatori di lavorare con i dati in un modo più intuitivo e orientato agli oggetti. Invece di scrivere query SQL grezze, puoi interagire con la tua base dati utilizzando LINQ (Language Integrated Query) e classi fortemente tipate.
Ora diamo un’occhiata ad un esempio di base. Immaginate di avere una classe Product
:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Questo è piuttosto semplice con solo tre campi. Utilizzando EF Core, puoi creare una classe di contesto che rappresenta una sessione con il database e include un DbSet
per ogni tipo di entità che vuoi interrogare o salvare:
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.Use<Your_SQL_Database_function>("YourConnectionStringHere");
}
}
Questo codice definisce una classe chiamata AppDbContext
che eredita dalla classe DbContext
di Entity Framework Core. Questa classe viene usata per interagire con il database. Dentro questa classe, viene definita una proprietà DbSet<Product>
chiamata Products
, che rappresenta una collezione di entità Product
e corrisponde ad una tabella chiamata Products
nel database. Il metodo OnConfiguring
viene sovrascritto per configurare la connessione al database; è possibile specificare diversi database come provider del database. Il metodo utilizza un optionsBuilder
per impostare la connessione con un placeholder per la stringa di connessione del database reale. Obviamente, questa stringa di connessione dovrà essere sostituita con quella reale che contiene i dettagli necessari per connettersi al database. Quando si crea un’istanza di AppDbContext
nell’applicazione, questa configurazione viene utilizzata per eseguire operazioni come query o salvataggio di entità Product
nella tabella Products
.
Con questa configurazione, è possibile eseguire operazioni CRUD (Create, Read, Update, Delete) utilizzando EF Core. Per esempio, per aggiungere un nuovo prodotto al database, è possibile utilizzare questo codice.
using (var context = new AppDbContext())
{
var product = new Product { Name = "Laptop", Price = 999.99M };
context.Products.Add(product);
context.SaveChanges();
}
Questo codice dimostra come aggiungere un nuovo prodotto alla database utilizzando Entity Framework Core. Viene creata un’istanza di AppDbContext
e all’interno di questo contesto, viene creato un nuovo oggetto Product
con il nome “Laptop” e il prezzo di 999,99. Questo nuovo prodotto viene quindi aggiunto alla collezione Products
gestita da AppDbContext
. Infine, viene chiamato il metodo SaveChanges
per salvare le modifiche al database, effettivamente inserendo il nuovo prodotto nella tabella Products
.
Per query di prodotti, è possibile utilizzare 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}");
}
}
Questo codice dimostra come utilizzare Entity Framework Core per query sul database. Viene creata un’istanza di AppDbContext
e all’interno di questo contesto, viene effettuata una query per recuperare tutti i prodotti con un prezzo superiore a 500. I risultati vengono memorizzati in una lista chiamata products
. Poi, un ciclo foreach iteratore attraverso ciascun prodotto nella lista, stampando il nome e il prezzo di ogni prodotto sul console.
EF Core si occupa di tradurre queste query LINQ negli appropriate comandi SQL per il tuo database, rendendo l’accesso ai dati più semplice e facile da mantenere.
EF Core supporta anche funzionalità avanzate come il tracking delle modifiche, il caricamento in background e le migrazioni, che aiutano a gestire i cambiamenti dello schema del database nel tempo.
In sintesi, EF Core è un potente ORM che semplifica l’accesso ai dati nelle applicazioni .NET consentendo di lavorare con i dati usando gli oggetti .NET e LINQ. Il suo supporto per più motori di database e la sua estensibilità lo rendono una scelta versatile per un ampio range di applicazioni.
Successivamente, vedremo come il provider MongoDB EF Core attraversa il gap tra MongoDB e EF Core, permettendoci di usare i familiari pattern di EF Core con una base di dati MongoDB.
Come il provider MongoDB EF Core attraversa il gap
Il provider MongoDB Entity Framework Core (EF Core) è uno strumento che consente agli sviluppatori di usare MongoDB con Entity Framework Core, combinando la flessibilità di MongoDB con gli API e i pattern di progettazione di EF Core. Questo provider vi permette di lavorare con MongoDB usando le stesse tecniche di codice-first e query LINQ che si userebbero con le basi di dati relazionali, semplificando lo sviluppo e riducendo la curva di apprendimento per chi già conosce EF Core.
Il provider MongoDB EF Core attraversa il gap tra MongoDB e EF Core supportando operazioni CRUD di base, query LINQ e documenti embedded, tra gli altri feature. Ecco alcune capacità chiave:
-
Workflow Codice-First: È possibile definire i modelli dati in C# e usare EF Core per generare lo schema di MongoDB invece di iniziare con lo schema database e generare il codice da esso. Questo è particolarmente utile per gli sviluppatori che preferiscono gestire la struttura della loro base dati attraverso il codice.
-
Operazioni CRUD: Il provider supporta operazioni di creazione, lettura, aggiornamento e eliminazione basilari. Per esempio, puoi aggiungere un nuovo record alla base dati utilizzando lo stesso codice visto prima:
using (var context = new AppDbContext()) { var product = new Product { Name = "Laptop", Price = 999.99M }; context.Products.Add(product); context.SaveChanges(); }
-
Supporto query LINQ
: Puoi usare LINQ per eseguire query su MongoDB, permettendoti di sfruttare le tue conoscenze esistenti di C# e .NET per interagire con il database.
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}"); } }
-
Tracking Modifiche: Le capacità di tracciamento delle modifiche di EF Core sono supportate, consentendo la rilevazione automatica e il salvataggio delle modifiche apportate alle entità dati.
-
Documenti Inclusi: Il provider supporta i documenti inclusi, permettendogli di memorizzare i dati correlati all’interno di un singolo documento, che è un pattern comune in MongoDB.
-
Mappatura delle Classi e Serializzazione: Le tue classi C# vengono mappate alle collezioni di MongoDB, con supporto per diversi tipi di dati e impostazioni di serializzazione per assicurarsi che i dati siano memorizzati correttamente.
Modellazione Dati e Operazioni CRUD con MongoDB Atlas
Adesso passerò velocemente ad un esempio su come utilizzare il provider MongoDB per EF Core. Ma presto, creerò un progetto completo in Visual Studio Code così puoi vedere tutto in contesto.
In questa sezione, esploreremo come definire modelli di dati e eseguire operazioni CRUD (Create, Read, Update, Delete) utilizzando il provider MongoDB Entity Framework Core (EF) con MongoDB Atlas. Questa integrazione consente di sfruttare la flessibilità di MongoDB insieme ai pattern familiari di EF Core.
Configurazione del tuo ambiente
Per iniziare, devi aggiungere i pacchetti NuGet necessari al tuo progetto:
dotnet add package MongoDB.EntityFrameworkCore
Il pacchetto MS EF Core e il driver MongoDB in C# vengono aggiunti come dipendenze quando aggiungi il provider MongoDB EF Core. questi pacchetti permettono all’applicazione di interagire con MongoDB tramite EF Core, utilizzando le stesse definizioni di contesto e entità che si utilizzerebbero con una database relazionale.
Configurazione di MongoDB Atlas
Prima di poter eseguire operazioni CRUD, devi configurare un cluster MongoDB Atlas e connettere la tua applicazione a esso.
Ecco i passaggi. Notare che li esaminerai in dettaglio quando creerai il progetto a breve.
-
Creare un account MongoDB Atlas: Fai il login per un account gratuito su MongoDB Atlas.
-
Creare un Cluster: Configurare un nuovo cluster. MongoDB Atlas offre una versione gratuita perfetta per sviluppo e applicazioni a scala ridotta.
-
Ottieni Stringa di Connessione: Recupera la stringa di connessione dall’interfaccia di amministrazione di MongoDB Atlas. Assomiglierà a qualcosa del genere:
mongodb+srv://<username>:<password>@cluster0.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
Modello dei dati
Defini una classe da utilizzare come modello per entità. Per questo esempio, creerai una classe Customer
:
public class Customer
{
public ObjectId Id { get; set; }
public String Name { get; set; }
public String Order { get; set; }
}
Questa classe Customer
rappresenta la struttura dei documenti memorizzati nella collezione MongoDB.
Crea una Classe DB Context
Per iniziare a usare Entity Framework Core, crea una classe di contesto che deriva da DBContext. L’istanza della classe derivata DbContext
rappresenta una sessione di database e viene utilizzata per query e salvataggio di istanze delle tue entità.
La classe DBContext
espone proprietà DBSet
che specificano le entità con cui puoi interagire mentre usi quel contesto.
Questo esempio crea un’istanza di una classe derivata da DBContext
e specifica l’oggetto Customer
come una proprietà 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");
}
}
Flusso di lavoro basato sul codice
Con il provider MongoDB per EF, è possibile utilizzare un flusso di lavoro basato sul codice. Ciò significa che definisci le tue classi prima, e EF Core si occuperà della creazione e della gestione dello schema sottostante di MongoDB. Questo è particolarmente utile per MongoDB, che non enforca un schema, consentendo strutture dati flessibili e dinamiche.
Usa MongoDB
Una volta creata una classe DBContext
, è necessario costruire un oggetto DbContextOptionsBuilder
e chiamare il suo metodo UseMongoDB()
. Questo metodo richiede due parametri: un’istanza di MongoClient
e il nome del database che contiene le collezioni con cui stai lavorando.
Il metodo UseMongoDB()
restituisce un oggetto DbContextOptions
. Passa la proprietà Options
the questo oggetto al costruttore della tua classe DBContext
.
var mongoClient = new MongoClient("<Your MongoDB Connection URI>");
var dbContextOptions =
new DbContextOptionsBuilder<MyDbContext>().UseMongoDB(mongoClient, "<Database Name");
var db = new MyDbContext(dbContextOptions.Options);
Operazioni CRUD
Ora vediamo come codificare le operazioni CRUD. Concentriamoci su ciascuna operazione individualmente.
Operazione di creazione
Per creare un nuovo documento in MongoDB, usi il metodo Add
sulla DbSet
e chiami SaveChanges
. Questo è un esempio di creazione di un nuovo cliente:
using (var context = new MyDbContext(options))
{
var customer = new Customer { Name = "Beau Carnes", Order = "Laptop" };
context.Customers.Add(customer);
context.SaveChanges();
}
Questo codice crea una nuova istanza di Customer
e la aggiunge alla collezione Customers
. Il metodo SaveChanges
salva il nuovo cliente nel database MongoDB.
Operazione di Lettura
Per leggere documenti dalla collezione MongoDB, è possibile utilizzare query LINQ sul DbSet
. Ecco un esempio per recuperare tutti i clienti:
using (var context = new MyDbContext(options))
{
var customers = context.Customers.ToList();
foreach (var customer in customers)
{
Console.WriteLine($"Customer: {customer.Name}, Order: {customer.Order}");
}
}
Questo codice recupera tutti i clienti dalla collezione Customers
e stampa le loro informazioni.
Operazione di Aggiornamento
Per aggiornare un documento esistente, si recupera il documento, modifica le sue proprietà e si chiama SaveChanges
. Ecco un esempio di aggiornamento di un ordine del cliente:
using (var context = new MyDbContext(options))
{
var customer = context.Customers.FirstOrDefault(c => c.Name == "Beau Carnes");
if (customer != null)
{
customer.Order = "Smartphone";
context.SaveChanges();
}
}
Questo codice trova il cliente chiamato “Beau Carnes” e aggiorna il suo ordine in “Smartphone”.
Operazione di Eliminazione
Per eliminare un documento, si recupera il documento, lo rimuove dal DbSet
e si chiama SaveChanges
. Ecco un esempio di eliminazione di un cliente:
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();
}
}
Questo codice trova il cliente chiamato “Beau Carnes” e lo elimina dalla collezione Customers
.
Tracciamento delle Modifiche
Le capacità di tracciamento delle modifiche di EF Core sono completamente supportate, consentendo aggiornamenti efficienti ai documenti. Quando si modifica un’entità e si chiama SaveChanges
, EF Core genera i comandi MongoDB necessari per aggiornare solo i campi modificati.
Utilizzando il provider MongoDB EF, è possibile integrare senza problemi il modello documentare flessibile di MongoDB con le capacità robuste di ORM di EF Core, fornendo una potente toolset per i developer .NET per costruire applicazioni moderne.
Tutorial
Ora mettiamo tutto insieme e creiamo un sistema di prenotazione per ristoranti.
Prerequisiti
Per seguire questo tutorial, avrai bisogno di qualcosa di più:
-
.NET 7.0.
-
Conoscenza di base di ASP.NET MVC e C#.
- Un account gratuito di MongoDB Atlas e un cluster di livello gratuito.
Creare il progetto
ASP.NET Core è un framework web molto flessibile, che consente di scaffoldare diversi tipi di applicazioni web con differenze minime in termini di loro UI o struttura. Per questo tutorial, creerò un progetto MVC che userà file statici e controller. Ci sono altri tipi di front-end che potresti usare, come React, ma MVC con viste .cshtml è quello più comunemente usato. Per creare il progetto, userò il .NET CLI:
dotnet new mvc -o RestRes
Poiché abbiamo usato il CLI, sebbene sia più semplice, crea solo il file csproj e non il file di soluzione che ci consente di aprire il progetto in Visual Studio, quindi correggiamo questo.
cd RestRes
dotnet new sln
dotnet sln .\RestRes.sln add .\RestRes.csproj
Aggiungere i pacchetti NuGet
Ora che abbiamo creato il nuovo progetto, vogliamo andare avanti e aggiungere i pacchetti NuGet necessari. O usando il gestore di pacchetti NuGet o usando il comando .NET CLI seguente, aggiungi il pacchetto MongoDB MongoDB.EntityFrameworkCore.
dotnet add package MongoDB.EntityFrameworkCore
Creare le modelle
Prima di iniziare a implementare i nuovi pacchetti appena aggiunti, dobbiamo creare i modelli che rappresentano le entità che vogliamo nel nostro sistema di prenotazione di ristoranti, che saranno ovviamente memorizzate in MongoDB Atlas come documenti. Nelle seguenti sottosezioni, creeremo i seguenti modelli:
-
Ristorante
-
Prenotazione
-
MongoDBSettings
Restaurant
Prima di tutto, dobbiamo creare il nostro modello di ristorante che rappresenterà i ristoranti che sono disponibili per essere prenotati nel nostro sistema.
-
Creare un nuovo file nella cartella Models chiamato Restaurant.cs.
-
Aggiungi il seguente codice:
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’attributo collection prima della classe indica all’applicazione quale collezione del database stiamo utilizzando. Questo ci permette di avere nomi o capitali diversi tra la nostra classe e la nostra collezione, se lo desideriamo.
Reservation
Dobbiamo anche creare una classe reservation per rappresentare tutte le prenotazioni che prendiamo nel nostro sistema.
-
Creare un nuovo file all’interno della cartella Models chiamato Reservation.cs.
-
Aggiungervi il seguente codice:
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
Anche se non sarà un documento nel nostro database, abbiamo bisogno di una classe modello per memorizzare le impostazioni relative a MongoDB in modo che possano essere utilizzate in tutta l’applicazione.
-
Creare un altro file in Models chiamato MongoDBSettings.cs.
-
Aggiungere il seguente codice:
namespace RestRes.Models
{
public class MongoDBSettings
{
public string AtlasURI { get; set; }
public string DatabaseName { get; set; }
}
}
Configurazione di EF Core
Questa è la parte eccitante. Inizieremo a implementare EF Core e sfrutteremo il nuovo provider MongoDB. Se già state familiarizzati con EF Core, parte di questo sarà familiare a voi.
RestaurantReservationDbContext
-
Creare una cartella Services e creare un file chiamato RestaurantReservationDbContext.cs.
-
Sostituire il codice all’interno dell’espressione con il seguente:
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>();
}
}
}
Se siete già familiarizzati con EF Core, questo vi apparirà familiare. La classe estende DbContext e creiamo proprietà DbSet che memorizzano i modelli che saranno anche presenti nel database. Anche noi sovrascriviamo il metodo OnModelCreating. Notate che, a differenza dell’utilizzo di SQL Server, non chiamiamo .ToTable(). Potremmo invece chiamare ToCollection, ma questo non è richiesto qui in quanto specificiamo la collezione utilizzando gli attributi sulle classi.
Aggiungere la stringa di connessione e i dettagli del database alle impostazioni dell’applicazione.
Prima avevamo creato un modello MongoDBSettings, e ora dobbiamo aggiungere i valori a cui le proprietà mappano nelle nostre appsettings.
-
Entrambi appsettings.json e appsettings.Development.json, aggiungere il seguente nuovo segmento:
"MongoDBSettings": { "AtlasURI": "mongodb+srv://<username>:<password>@<url>", "DatabaseName": "restaurants" }
-
Sostituire l’URI Atlas con la propria stringa di connessione da Atlas.
Aggiornamento program.cs
Ora che abbiamo configurato i nostri modelli e il DbContext, è il momento di aggiungerli al nostro file program.cs.
Dopo la riga esistente builder.Services
.AddControllersWithViews();
, aggiungere il seguente codice:
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 ?? ""));
Creazione servizi
Ora è il momento di aggiungere i servizi che useremo per comunicare con il database attraverso il RestaurantBookingDbContext che abbiamo creato. Per ciascun servizio, creeremo un’interfaccia e la classe che la implementa.
IRestaurantService e RestaurantService
La prima interfaccia e il primo servizio che implementeremo si occupa delle operazioni CRUD sulla raccolta dei ristoranti. Questo è noto come pattern repository. Si può vedere gente interagire direttamente con il DbContext. Ma la maggior parte delle persone usa questo pattern, ed è il motivo per cui lo includiamo qui.
-
Se non lo avete già fatto, create una cartella Services per memorizzare le nostre nuove classi.
-
Crea un’interfaccia IRestaurantService e aggiungi il seguente codice per i metodi che implementeremo:
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);
}
}
-
Crea un file di classe per RestaurantService.
-
Aggiorna la dichiarazione della classe RestaurantService in modo che implementi l’IRestaurantService appena creato:
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 e ReservationService
Il prossimo è il nostro IReservationService e ReservationService.
Crea l’interfaccia IReservationService e aggiungi i seguenti metodi:
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);
}
}
Creare la classe ReservationService e sostituire il tuo codice con il seguente che implementa tutti i metodi:
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);
}
}
}
Questo codice è molto simile al codice per la classe RestaurantService ma riguarda le prenotazioni invece.
Aggiungendole al Contenitore di Iniezione di Dipendenze
L’ultimo passo per i servizi è aggiungerli al contenitore di iniezione di dipendenze.
Dentro Program.cs, aggiungere il seguente codice dopo il codice che hai aggiunto prima:
builder.Services.AddScoped<IRestaurantService, RestaurantService>();
builder.Services.AddScoped<IReservationService, ReservationService>();
Creando le view models
Prima di implementare il front end, abbiamo bisogno di aggiungere le view models che agiranno da messaggero tra il nostro front end e back end dove richiesto. Anche se il nostro applicativo è piuttosto semplice, la realizzazione della view model è ancora una buona pratica poiché aiuta a de-coupling i pezzi dell’app.
RestaurantListViewModel
La prima che aggiungeremo è la RestaurantListViewModel. sarà usata come modello nella nostra pagina Razor in un secondo momento per elencare i ristoranti nel nostro database.
-
Creare una nuova cartella in radice del progetto chiamata ViewModels.
-
Aggiungere un nuovo file chiamato RestaurantListViewModel.cs.
-
Aggiungere il seguente codice:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantListViewModel
{
public IEnumerable<Restaurant>? Restaurants { get; set; }
}
}
RestaurantAddViewModel
Vogliamo anche una view model che può essere usata dalla view Add che aggiungeremo più tardi.
-
Dentro la cartella ViewModels, creare un nuovo file chiamato RestaurantAddViewMode.cs.
-
Aggiunto:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantAddViewModel
{
public Restaurant? Restaurant { get; set; }
}
}
ReservationListViewModel
Ora, vogliamo fare qualcosa di simile per le prenotazioni, iniziando con ReservationListViewModel.
-
Creare un nuovo file nella cartella ViewModels chiamato ReservationListViewModel.cs.
-
Aggiunto:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationListViewModel
{
public IEnumerable<Reservation>? Reservations { get; set; }
}
}
ReservationAddViewModel
Infine, abbiamo il nostro ReservationAddViewModel.
Creare il file e aggiungere questo codice:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationAddViewModel
{
public Reservation? Reservation { get; set; }
}
}
Aggiunto a _ViewImports
Successivamente, aggegheremo riferimenti ai nostri modelli e viewmodel nei file delle viste. Per far sapere all’applicazione cosa sono, dobbiamo aggiungerli in _ViewImports.cshtml nella cartella Views.
Ci saranno già alcuni riferimenti in questo file, inclusi i TagHelpers, quindi vogliamo aggiungere i riferimenti alle nostre cartelle .Models e .ViewModels. Quindi la parte iniziale del file dovrebbe apparire così:
@using RestRes
@using RestRes.Models
@using RestRes.ViewModels
Creazione dei controller
Ora che abbiamo l’implementazione backend e i viewmodel ai quali fare riferimento, possiamo cominciare a lavorare verso il frontend. Creare due controller: uno per il ristorante e uno per la prenotazione.
RestaurantController
Il primo controller che aggiungeremo è quello per il ristorante.
-
Nella cartella esistente Controllers, aggiungi un nuovo file di controller chiamato RestaurantController.cs. Se state usando Visual Studio, utilizzate il modello di controller MVC vuoto.
-
Aggiungi questo codice:
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
Ora per il controller delle prenotazioni. Questo è molto simile al RestaurantController, ma ha una referenza sia al ristorante che al servizio di prenotazione, poiché abbiamo bisogno di associare un ristorante a una prenotazione. Questo perché al momento, il provider EF Core non supporta le relazioni tra entità, quindi possiamo relazionare le entità in un modo diverso.
-
Crea un altro file di controller MVC vuoto chiamato ReservationController.cs.
-
Incolla il seguente codice:
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);
}
}
}
Creando le viste
Ora che abbiamo preparato il back-end e i controller con gli endpoint del nostro sistema di prenotazione per il ristorante, è giunto il momento di implementare le viste. Questo sarà fatto utilizzando le pagine Razor. Vedrete anche riferimenti a classi da Bootstrap, poiché questo è il framework CSS che viene fornito con le applicazioni MVC. Forniremmo viste per le operazioni CRUD sia per le liste che per le prenotazioni.
Elenco ristoranti
Prima di tutto, forniremo una visualizzazione che mapperà alla root di /Ristorante, che secondo la convenzione userà il metodo Index che abbiamo implementato.
ASP.NET Core MVC utilizza un modello di convenzione secondo il quale si denomina il file .cshtml con il nome dell’endpoint/metodo che utilizza e si trova in una cartella che porta il suo nome.
-
Nella cartella Views, creare una nuova sottocartella chiamata Ristorante.
-
In questa cartella Ristorante, aggiungere una nuova visualizzazione creando un file chiamato
Index.cshtml
. Se si utilizzano le template disponibili, si desidera Visualizzazione Razor – Vuota. Denominare la visualizzazione Index. -
Aggiungere questo codice:
@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>
Adesso aggiorniamo la route predefinita da Home a /Ristorante.
In Program.cs, dentro app.MapControllerRoute
, sostituire la riga del pattern con il seguente:
pattern: "{controller=Restaurant}/{action=Index}/{id?}");
Se avessimo eseguito questo adesso, i pulsanti condirebbero a 404 perché non li abbiamo ancora implementati. Quindi facciamolo ora.
Aggiunta ristoranti
Inizieremo con il modulo per l’aggiunta di nuovi ristoranti.
-
Aggiungere una nuova visualizzazione vuota Razor nella sottocartella Ristorante chiamata Add.cshtml.
-
Aggiungi il seguente codice:
@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>
Modifica ristoranti
Il codice per la pagina di modifica è quasi identico a quello per l’aggiunta, ma utilizza il ristorante come modello poiché userà il ristorante passato per pre-popolare il modulo per la modifica.
-
Aggiungi un’altra vista all’interno della sottocartella Ristorante chiamata Edit.cshtml.
-
Aggiungi il seguente codice:
@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>
Eliminazione ristoranti
La pagina finale che dobbiamo implementare è la pagina che viene chiamata quando viene cliccato il pulsante elimina.
-
Crea una nuova vista vuota chiamata Delete.cshtml.
-
Aggiungi il seguente codice:
@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>
Elenco prenotazioni
Abbiamo aggiunto le viste per i ristoranti, quindi ora aggiungeremo le viste per le prenotazioni, iniziando con l’elenco di eventuali prenotazioni esistenti.
-
Crea una nuova cartella all’interno della cartella Viste chiamata Prenotazione.
-
Crea un nuovo file vuoto di vista chiamato Index.cshtml.
-
Aggiungi il seguente codice per mostrare le prenotazioni, se presenti:
@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>
}
Aggiunta prenotazioni
Aggiunta delle prenotazioni è successiva.
-
Creare una vista vuota chiamata Add.cshtml.
-
Aggiungere il seguente codice:
@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>
Modifica delle prenotazioni
La modifica delle prenotazioni è successiva.
-
Creare una vista vuota chiamata Edit.cshtml.
-
Aggiungere il seguente codice:
@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>
Eliminazione delle prenotazioni
L’eliminazione delle prenotazioni è successiva.
-
Creare una vista vuota chiamata Delete.cshtml.
-
Aggiungere il seguente codice:
@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>
Aggiornamento della NavBar
L’ultima cosa da aggiungere è aggiornare la barra di navigazione dell’applicazione in modo da poter passare facilmente tra ristoranti e prenotazioni.
Navigare al file presente in Views/Shared/_Layout.cshtml
. Trovare il div
con la classe navbar-collapse
. rimuovere quella sezione intera e aggiungere il seguente codice:
<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>
Testing della nostra applicazione
Ora abbiamo una applicazione funzionante che utilizza il nuovo MongoDB Provider per EF Core. Ora è il momento di testarla tutta e visitare i nostri endpoint per assicurarci che tutto funzioni.
Nel terminal eseguire il seguente comando:
dotnet run
Prova a modificare i ristoranti e ad aggiungere prenotazioni. Poi puoi navigare alla pagina del database MongoDB Atlas e vedere che i tuoi cambiamenti sono riflessi nel database.
Operazioni avanzate di MongoDB: Ricerca Atlas e Ricerca vettoriale
Il provider EF Core è costruito sopra il driver MongoDB C#. Poiché già hai accesso al MongoClient durante la creazione del DbContext, questo ti permette di eseguire operazioni avanzate di MongoDB come la Ricerca Atlas e la Ricerca vettoriale. Queste funzionalità migliorano le capacità dell’applicazione permettendo funzioni di ricerca potenti mentre si sfrutta ancora il famoso framework EF Core.
Ricerca Atlas
Ricerca Atlas è un motore di ricerca full-text fornito da MongoDB Atlas. Permette di eseguire query di ricerca sofisticate sul tuo dati MongoDB. Con la Ricerca Atlas, puoi implementare funzioni come l’autocompletamento, la ricerca per categorie e l’ordinamento in base alla relevanza.
Per usare la Ricerca Atlas con il provider EF Core, segui questi passaggi:
-
Impostare gli indici in MongoDB Atlas:
-
Vai al tuo cluster MongoDB Atlas.
-
Naviga alla scheda “Ricerca” e crea un nuovo indice sulla tua collezione. Definisci i campi che vuoi rendere ricercabili.
-
-
Definisci i Campi Ricercabili nei Tuoi Modelli: Nei tuoi modelli C#, assicurati che i campi che vuoi cercare siano definiti correttamente. Ecco un esempio della definizione di un modello Product.
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; } }
-
Esecuzione di Query di Ricerca: Utilizza le capacità del driver MongoDB .NET per eseguire ricerche testuali. Poiché EF Core stesso non supporta direttamente la sintassi di ricerca specifica di MongoDB, dovrai utilizzare il driver in combinazione con EF Core. Ecco un esempio:
using MongoDB.Driver; using MongoDB.Driver.Linq; var client = new MongoClient("your-mongodb-connection-string"); var database = client.GetDatabase("your-database-name"); var collection = database.GetCollection<Product>("Products"); var searchResult = collection.Aggregate() .Match(Builders<Product>.Filter.Text("search term")) .ToList();
Questo esempio mostra come eseguire una ricerca testuale sulla collezione Products
. Il filtro Text
aiuta a cercare attraverso tutti i campi indicizzati definiti nel tuo indice di ricerca di Atlas Search.
Ricerca Vettoriale
La Ricerca Vettoriale in MongoDB viene utilizzata per cercare documenti in base alla similitudine tra vettori, che è particolarmente utile per applicazioni coinvolgenti machine learning, raccomandazioni e processamento del linguaggio naturale. La Ricerca Vettoriale consente di interrogare documenti utilizzando vettori che rappresentano testo, immagini o altri dati ad alta dimensione.
-
Creare e Memorizzare Vettori: Prima di tutto, assicurati che i tuoi documenti contengano vettori. Potrebbe essere necessario preprocessare i tuoi dati per generare questi vettori utilizzando modelli di machine learning.
-
Indicizzare Vettori in MongoDB Atlas: Crea un indice speciale sul campo vettoriale in MongoDB Atlas per consentire ricerche simili vettoriali efficienti.
-
Effettuare ricerche vettoriali: Utilizzare il driver .NET di MongoDB per effettuare query basate sulla similarità dei vettori.
Integrazione con EF Core
Anche se il provider EF Core di MongoDB semplifica le operazioni CRUD, alcune funzionalità avanzate come Atlas Search e Vector Search richiedono l’uso diretto del driver .NET di MongoDB. Tuttavia, è ancora possibile integrare queste operazioni all’interno della tua applicazione basata su EF Core utilizzando il driver per le funzionalità di ricerca e EF Core per altre attività di gestione dei dati.
Combina EF Core e le funzionalità avanzate di MongoDB per creare applicazioni potenti e flessibili che sfruttano il meglio di entrambi i mondi: i modelli di accesso ai dati strutturati di EF Core e le potenti capacità di ricerca di MongoDB Atlas.
Source:
https://www.freecodecamp.org/news/using-entity-framework-core-with-mongodb/