Entity Framework Core es un popular ORM (Object-Relational Mapper) para aplicaciones .NET, que permite a los desarrolladores trabajar con bases de datos usando objetos .NET. Puede utilizarse con muchos tipos de bases de datos, incluyendo MongoDB.
En este artículo, aprenderá cómo utilizar Entity Framework Core con MongoDB. Este artículo cubre los conceptos básicos, explica los beneficios y proporciona un tutorial paso a paso. Sea nuevo en MongoDB o Entity Framework Core, o solo busque integrar estas herramientas en sus proyectos .NET, este guía le ayudará a construir el puente entre las bases de datos relacionales y las bases de datos NoSQL.
El artículo comienza con una breve introducción a MongoDB, así como una introducción a Entity Framework Core de Microsoft. Luego, cubre cómo usar el proveedor MongoDB EF Core. Después de pasar por detalles técnicos con algunos ejemplos básicos, creará un proyecto completo con MongoB y Entity Framework Core para ver cómo todo funciona juntos. El proyecto utilizará datos de muestra de MongoDB Atlas para crear un sistema de reservas de restaurantes.
También hay una versión de video de este artículo que puede ver en el canal de YouTube de freeCodeCamp.org.
Introducción a MongoDB
MongoDB es una popular base de datos NoSQL diseñada para manejar grandes volúmenes de datos y proporcionar alta performance, escalabilidad y flexibilidad. A diferencia de las bases de datos relacionales tradicionales, MongoDB almacena datos en documentos flexibles y similares a JSON. Este enfoque documental permite almacenar estructuras de datos complejas de una manera más natural e intuitiva.
En MongoDB, los datos se almacenan en colecciones, que son similares a las tablas en las bases de datos relacionales pero sin un esquema fijo. Esto significa que puedes tener documentos con diferentes estructuras en la misma colección. Esta flexibilidad es una de las ventajas clave de utilizar MongoDB, especialmente cuando se trata de datos no estructurados o semi-estructurados.
Veamos un ejemplo de un documento de MongoDB. Imagina que tenemos una colección llamada users
que almacena información sobre los usuarios en una aplicación. Aquí es cómo podría verse un documento típico:
{
"_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"]
}
En este documento, tenemos varios campos como name
, email
, age
, y address
. El campo address
en sí es un documento anidado que contiene varios subcampos como street
, city
, state
, y zip
. Además, el campo hobbies
es un array de strings.
Aunque esto se parece a JSON, MongoDB almacena datos en un formato binario llamado BSON (Binary JSON). BSON extende el modelo JSON para proporcionar tipos de datos adicionales, como enteros, flotantes, fechas y datos binarios. Este formato binario está optimizado para la eficiencia y la flexibilidad, lo que permite a MongoDB almacenar y recuperar datos de manera eficiente.
Otra característica importante de MongoDB es su capacidad para escalar horizontalmente. Esto significa que puedes distribuir tus datos entre varios servidores, lo que facilita la administración de grandes conjuntos de datos y garantiza alta disponibilidad. MongoDB también admite consultas ricas, índices y agregación, lo que lo hace una herramienta poderosa para una amplia gama de aplicaciones.
Por ejemplo, puedes realizar una consulta para encontrar a todos los usuarios que viven en una ciudad específica:
db.users.find({ "address.city": "Anytown" })
O puedes encontrar usuarios que tienen un hobby específico:
db.users.find({ "hobbies": "coding" })
MongoDB es ampliamente utilizado en varias industrias, desde el comercio electrónico y la gestión de contenidos hasta el análisis en tiempo real y aplicaciones de Internet of Things (IoT). Su flexibilidad y escalabilidad lo hacen una opción excelente para aplicaciones modernas que necesitan manejar datos diversos y dinámicos.
Ahora que hemos adquirido un entendimiento básico de qué es MongoDB y por qué es popular, vamos a avanzar a otro herramienta fundamental en nuestra pila tecnológica: el Entity Framework Core de Microsoft.
Introducción al Entity Framework Core de Microsoft
Entity Framework Core, a menudo abreviado como EF Core, es un moderno mapeador objeto-base de datos para .NET. Permite a los desarrolladores trabajar con una base de datos utilizando objetos de .NET, eliminando la necesidad de la mayoría del código de acceso a datos que los desarrolladores generalmente deben escribir.
EF Core es una versión ligera, extensible y multiplataforma de la popular tecnología de acceso a datos Entity Framework (EF). Soporta una variedad de motores de base de datos, incluyendo SQL Server, SQLite y MongoDB.
Uno de los principales beneficios de utilizar EF Core es que permite a los desarrolladores trabajar con datos de manera más intuitiva y orientada a objetos. En lugar de escribir consultas SQL en crudo, puedes interactuar con tu base de datos utilizando LINQ (Language Integrated Query) y clases con tipado fuerte.
Veamos un ejemplo básico. Imagina que tenemos una clase Product
:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Este es muy simple solo con tres campos. Utilizando EF Core, puedes crear una clase de contexto que representa una sesión con la base de datos y incluye un DbSet
para cada tipo de entidad que desees consultar o guardar:
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.Use<Your_SQL_Database_function>("YourConnectionStringHere");
}
}
Este código define una clase llamada AppDbContext
que hereda de la clase DbContext
de Entity Framework Core. Esta clase se utiliza para interactuar con la base de datos. Dentro de esta clase, hay una propiedad de DbSet<Product>
llamada Products
, que representa una colección de entidades de Product
y corresponde a una tabla llamada Products
en la base de datos. El método OnConfiguring
se sobreescribe para configurar la conexión de base de datos, puede especificar varios tipos de bases de datos como proveedor de base de datos. El método utiliza un optionsBuilder
para configurar la conexión con un marcador de posición para la cadena de conexión de base de datos real. Esta cadena de conexión obviamente debe ser reemplazada con la real que contenga los detalles necesarios para conectar con la base de datos. Cuando se crea una instancia de AppDbContext
en la aplicación, utiliza esta configuración para realizar operaciones como consultar o guardar entidades de Product
en la tabla Products
.
Con este ajuste, puede realizar operaciones CRUD (Create, Read, Update, Delete) utilizando EF Core. Por ejemplo, para agregar un nuevo producto a la base de datos, se puede utilizar este código.
using (var context = new AppDbContext())
{
var product = new Product { Name = "Laptop", Price = 999.99M };
context.Products.Add(product);
context.SaveChanges();
}
Este código muestra cómo agregar un nuevo producto a la base de datos utilizando Entity Framework Core. Se crea una instancia de AppDbContext
y dentro de este contexto, se instancia un nuevo objeto Product
con el nombre “Laptop” y un precio de 999.99. Este nuevo producto luego se agrega a la colección Products
gestionada por el AppDbContext
. Finalmente, se llama al método SaveChanges
para guardar los cambios en la base de datos, efectivamente insertando el nuevo producto en la tabla Products
.
Para consultar productos, se puede utilizar 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}");
}
}
Este código muestra cómo consultar la base de datos utilizando Entity Framework Core. Se crea una instancia de AppDbContext
y dentro de este contexto, se realiza una consulta para obtener todos los productos con un precio superior a 500. Los resultados se almacenan en una lista llamada products
. A continuación, un bucle recorre cada producto de la lista, imprimiendo en la consola el nombre y el precio de cada producto.
EF Core se encarga de traducir estas consultas LINQ en los comandos SQL apropiados para su base de datos, haciendo que el acceso a datos sea más sencillo y mantenible.
EF Core también ofrece características avanzadas como el seguimiento de cambios, carga perezosa y migraciones, que le ayudan a manejar cambios en el esquema de base de datos a lo largo del tiempo.
En resumen, EF Core es una potente ORM que simplifica el acceso a datos en aplicaciones .NET al permitir trabajar con sus datos utilizando objetos .NET y LINQ. Su soporte para varios motores de base de datos y su extensibilidad lo hacen una opción versátil para una amplia gama de aplicaciones.
A continuación, verás cómo el proveedor MongoDB EF Core elimina la brecha entre MongoDB y EF Core, permitiéndonos utilizar los patrones familiares de EF Core con una base de datos de MongoDB.
Cómo el Proveedor MongoDB EF Core elimina la brecha
El proveedor MongoDB Entity Framework Core (EF Core) es una herramienta que permite a los desarrolladores utilizar MongoDB con Entity Framework Core (EF Core), combinando la flexibilidad de MongoDB con los patrones de API y diseño familiares de EF Core. Este proveedor te permite trabajar con MongoDB utilizando las mismas técnicas de creación de datos y consultas LINQ que utilizarías con bases de datos relacionales, simplificando el desarrollo y reduciendo la pendiente de aprendizaje para aquellos que ya están familiarizados con EF Core.
El proveedor MongoDB EF Core elimina la brecha entre MongoDB y EF Core al admitir operaciones CRUD básicas, consultas LINQ y documentos embebidos, entre otras características. Aquí están algunas capacidades clave:
-
Flujos de trabajo Code-First: Puedes definir tus modelos de datos en C# y utilizar EF Core para generar el esquema de MongoDB, en lugar de comenzar con el esquema de base de datos y generar código de él. Esto es particularmente útil para desarrolladores que prefieren administrar su estructura de base de datos a través de código.
-
Operaciones CRUD: El proveedor admite operaciones básicas de creación, lectura, actualización y eliminación. Por ejemplo, puedes agregar un nuevo registro a la base de datos usando el mismo código que vimos anteriormente:
using (var context = new AppDbContext()) { var producto = new Product { Name = "Laptop", Price = 999.99M }; context.Products.Add(producto); context.SaveChanges(); }
-
Soporte de consultas LINQ: Puede usar LINQ para realizar consultas contra MongoDB, lo que le permite aprovechar su conocimiento existente de C# y .NET para interactuar con la base de datos.
using (var context = new AppDbContext()) { var products = context.Products.Where(p => p.Price > 500).ToList(); foreach (var product in products) { Console.WriteLine($"Producto: {product.Name}, Precio: {product.Price}"); } }
-
Seguimiento de cambios: Las capacidades de seguimiento de cambios de EF Core son compatibles, permitiendo la detección automática y la salvaguarda de los cambios realizados en tus entidades de datos.
-
Documentos embebidos: El proveedor admite documentos embebidos, lo que te permite almacenar datos relacionados dentro de un solo documento, lo cual es un patrón común en MongoDB.
-
Mapeo de clases y serialización: Tus clases C# se mapean a colecciones de MongoDB, con soporte para varios tipos de datos y configuraciones de serialización para asegurar que los datos se almacenan correctamente.
Modelado de datos y operaciones CRUD usando MongoDB Atlas
Ahora veremos un ejemplo rápido sobre cómo usar el proveedor de MongoDB para EF Core. Pero pronto, crearemos un proyecto completo en Visual Studio Code para que puedas ver todo en contexto.
En esta sección, exploraremos cómo definir modelos de datos y realizar operaciones CRUD (Create, Read, Update, Delete) utilizando el proveedor MongoDB Entity Framework Core (EF) con MongoDB Atlas. Esta integración permite aprovechar la flexibilidad de MongoDB con los patrones familiares de EF Core.
Configuración de tu Entorno
Para comenzar, necesitas agregar las paquetes NuGet necesarios a tu proyecto:
dotnet add package MongoDB.EntityFrameworkCore
El paquete MS EF Core y el Controlador C# de MongoDB se agregarán como dependencias cuando agregues el paquete proveedor de MongoDB EF Core. Estos paquetes permiten que tu aplicación interaccione con MongoDB a través de EF Core, utilizando las mismas definiciones de contexto y entidades que usarías con una base de datos relacional.
Configuración de MongoDB Atlas
Antes de poder realizar operaciones CRUD, necesitas configurar un clúster de MongoDB Atlas y conectar tu aplicación a él.
Aquí están los pasos. Teng en cuenta que revisaremos estos detalladamente cuando cree el proyecto próximamente.
-
Crear una Cuenta de MongoDB Atlas: Regístrate para una cuenta gratuita en MongoDB Atlas.
-
Crear un Cluster: Establecer un nuevo cluster. MongoDB Atlas ofrece una capa gratuita perfecta para desarrollo y aplicaciones de pequeña escala.
-
Obtener Cadena de Conexión: Obtenga su cadena de conexión del panel de MongoDB Atlas. Podría parecerse a esto:
mongodb+srv://<username>:<password>@cluster0.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
Modelando los Datos
Defina una clase para utilizarla como modelo para su entidad. En este ejemplo, crearemos una clase Cliente
:
public class Customer
{
public ObjectId Id { get; set; }
public String Name { get; set; }
public String Order { get; set; }
}
Esta clase Cliente
representa la estructura de los documentos almacenados en la colección de MongoDB.
Crear una Clase de Contexto de BD
Para empezar a usar Entity Framework Core, cree una clase de contexto que derive de DBContext. La instancia de la clase derivada DbContext
representa una sesión de base de datos y se utiliza para consultar y guardar instancias de sus entidades.
La clase DBContext
expone propiedades de DBSet
que especifican las entidades con las que puede interactuar mientras utiliza ese contexto.
Este ejemplo crea una instancia de una clase derivada de DBContext
y especifica el objeto Customer
como una propiedad 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");
}
}
Flujo de trabajo de primero en código
Con el proveedor MongoDB de EF, puede utilizar un flujo de trabajo de primero en código. Esto significa que primero define sus clases, y EF Core maneja la creación y administración de la estructura subyacente de MongoDB. Esto es particularmente útil para MongoDB, que no aplica ninguna restricción de esquema, permitiendo estructuras de datos flexibles y dinámicas.
Utilizar MongoDB
Una vez que haya creado una clase DBContext
, necesita construir un objeto DbContextOptionsBuilder
y llamar a su método UseMongoDB()
. Este método toma dos parámetros: una instancia de MongoClient
y el nombre de la base de datos que almacena las colecciones con las que está trabajando.
El método UseMongoDB()
devuelve un objeto DbContextOptions
. Transfiera la propiedad Options
theste objeto al constructor de su clase DBContext
.
var mongoClient = new MongoClient("<Your MongoDB Connection URI>");
var dbContextOptions =
new DbContextOptionsBuilder<MyDbContext>().UseMongoDB(mongoClient, "<Database Name");
var db = new MyDbContext(dbContextOptions.Options);
Operaciones CRUD
Ahora veamos cómo codificar las operaciones CRUD. Solo nos centraremos en cada operación individualmente.
Operación de creación
Para crear un nuevo documento en MongoDB, utiliza el método Add
en el DbSet
y llama a SaveChanges
. Este es un ejemplo de crear un nuevo cliente:
using (var context = new MyDbContext(options))
{
var customer = new Customer { Name = "Beau Carnes", Order = "Laptop" };
context.Customers.Add(customer);
context.SaveChanges();
}
Este código crea una nueva instancia de Customer
y la agrega a la colección Customers
. El método SaveChanges
guarda el nuevo cliente en la base de datos MongoDB.
Operación de lectura
Para leer documentos de la colección de MongoDB, puedes usar consultas LINQ sobre el DbSet
. Este es un ejemplo de cómo obtener todos los clientes:
using (var context = new MyDbContext(options))
{
var customers = context.Customers.ToList();
foreach (var customer in customers)
{
Console.WriteLine($"Customer: {customer.Name}, Order: {customer.Order}");
}
}
Este código obtiene todos los clientes de la colección Customers
y muestra sus detalles.
Operación de actualización
Para actualizar un documento existente, primero debes recuperar el documento, modificar sus propiedades y luego llamar a SaveChanges
. Este es un ejemplo de cómo actualizar una orden de un 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();
}
}
Este código encuentra al cliente llamado “Beau Carnes” y actualiza su orden a “Smartphone”.
Operación de eliminación
Para eliminar un documento, primero debes recuperar el documento, eliminarlo de la DbSet
y luego llamar a SaveChanges
. Este es un ejemplo de cómo eliminar a 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();
}
}
Este código encuentra al cliente llamado “Beau Carnes” y lo elimina de la colección Customers
.
Seguimiento de cambios
Las capacidades de seguimiento de cambios de EF Core están totalmente soportadas, lo que permite actualizaciones eficientes de documentos. Cuando modificas una entidad y llamas a SaveChanges
, EF Core generará las órdenes necesarias de MongoDB para actualizar solo los campos cambiados.
Al usar el proveedor MongoDB de EF, puedes integrar sin problemas el flexible modelo de documentos de MongoDB con las capacidades robustas de ORM de EF Core, proporcionando una potente herramienta para los desarrolladores de .NET para construir aplicaciones modernas.
Tutorial
Ahora vamos a poner todo juntos y crear un sistema de reservas de restaurantes.
Prerrequisitos
Para seguir este tutorial, necesitarás algunas cosas:
-
.NET 7.0.
-
Conocimientos básicos de ASP.NET MVC y C#.
-
Cuenta gratuita de MongoDB Atlas y cluster de nivel gratuito.
Crear el proyecto
ASP.NET Core es un marco web muy flexible, que permite escalar diferentes tipos de aplicaciones web con pequeñas diferencias en términos de su interfaz de usuario o estructura. Para este tutorial, vamos a crear un proyecto MVC que utilizará archivos estáticos y controladores. Existen otros tipos de front-end que podría utilizar, como React, sin embargo, MVC con vistas .cshtml es el más comúnmente utilizado. Para crear el proyecto, vamos a usar la CLI de .NET:
dotnet new mvc -o RestRes
Debido a que utilizamos la CLI, aunque es más fácil, solo crea el archivo csproj y no el archivo de solución que nos permite abrirlo en Visual Studio, así que lo corregiremos.
cd RestRes
dotnet new sln
dotnet sln .\RestRes.sln add .\RestRes.csproj
Agregar paquetes NuGet
Ahora que hemos creado el nuevo proyecto, desearemos agregar los paquetes NuGet requeridos. ya sea utilizando el Administrador de Paquetes NuGet o utilizando la orden de la CLI de .NET de abajo, agregue el paquete MongoDB MongoDB.EntityFrameworkCore.
dotnet add package MongoDB.EntityFrameworkCore
Crear las modelos
Antes de poder comenzar a implementar los nuevos paquetes que acabamos de agregar, necesitamos crear las modelos que representan las entidades que queremos en nuestro sistema de reservas de restaurantes, que por supuesto serán almacenadas como documentos en MongoDB Atlas. En las siguientes subsecciones, crearemos los siguientes modelos:
-
Restaurant
-
Reservation
-
MongoDBSettings
Restaurant
Primero, necesitamos crear nuestro modelo de restaurante que representará los restaurantes disponibles para ser reservados en nuestro sistema.
-
Cree un nuevo archivo en la carpeta Models llamado Restaurant.cs.
-
Agregue el siguiente código:
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; }
}
}
El atributo de colección antes de la clase le dice a la aplicación qué colección dentro de la base de datos estamos usando. Esto nos permite tener nombres o mayúsculas diferentes entre nuestra clase y nuestra colección si queremos.
Reservation
También necesitamos crear una clase de reserva para representar cualquier reserva que tomemos en nuestro sistema.
-
Cree un nuevo archivo dentro de la carpeta Models llamado Reservation.cs.
-
Agregue el siguiente código a él:
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
Aunque no será un documento en nuestra base de datos, necesitamos una clase de modelo para almacenar nuestras configuraciones relacionadas con MongoDB para que puedan ser utilizadas en toda la aplicación.
-
Cree otro archivo en Models llamado MongoDBSettings.cs.
-
Agregue el siguiente código:
namespace RestRes.Models
{
public class MongoDBSettings
{
public string AtlasURI { get; set; }
public string DatabaseName { get; set; }
}
}
Configuración de EF Core
Esta es la parte emocionante. Vamos a comenzar a implementar EF Core y aprovechar el nuevo proveedor de MongoDB. Si ya está acostumbrado a trabajar con EF Core, parte de esto le resultará familiar.
RestaurantReservationDbContext
-
Cree una carpeta llamada Services, y luego cree un archivo llamado RestaurantReservationDbContext.cs.
-
Reemplace el código dentro del namespace con lo siguiente:
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 está acostumbrado a EF Core, esto le resultará familiar. La clase extiende DbContext y creamos propiedades DbSet que almacenan los modelos que también estarán presentes en la base de datos. También sobrescribimos el método OnModelCreating. Podrá notar que a diferencia de cuando se utiliza SQL Server, no llamamos a .ToTable(). Podríamos llamar a ToCollection en su lugar, pero esto no es necesario aquí ya que especificamos la colección usando atributos en las clases.
Agregue la cadena de conexión y los detalles de la base de datos a appsettings.
Anteriormente creamos un modelo de MongoDBSettings, y ahora necesitamos agregar los valores que las propiedades mapean a nuestro appsettings.
-
Tanto en appsettings.json como en appsettings.Development.json, agregue la siguiente nueva sección:
"MongoDBSettings": { "AtlasURI": "mongodb+srv://<username>:<password>@<url>", "DatabaseName": "restaurants" }
-
Reemplaza la URI de Atlas con tu propia cadena de conexión de Atlas.
Actualizando program.cs
Ahora que hemos configurado nuestros modelos y DbContext, es hora de agregarlos a nuestro archivo program.cs.
Después de la línea existente builder.Services
.AddControllersWithViews();
, agregue el siguiente código:
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 ?? ""));
Creando los servicios
Ahora es hora de agregar los servicios que utilizaremos para hablar con la base de datos a través del RestaurantBookingDbContext que creamos. Para cada servicio, creamos una interfaz y la clase que la implementa.
IRestaurantService y RestaurantService
La primera interfaz y servicio que implementaremos es para realizar operaciones CRUD en la colección de restaurantes. Este patrón se conoce como el patrón de repositorio. Puede que vea a personas interactuar directamente con el DbContext. Pero la mayoría de la gente utiliza este patrón, por lo que es por qué lo incluimos aquí.
-
Si aún no lo ha hecho, cree una carpeta Services para almacenar nuestras nuevas clases.
-
Cree una interfaz IRestaurantService y agregue el siguiente código para los métodos que implementaremos:
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);
}
}
-
Cree un archivo de clase para la clase RestaurantService.
-
Actualice la declaración de la clase RestaurantService para que implemente la interfaz IRestaurantService que acabamos de crear:
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 y ReservationService
La próxima en nuestro listado es nuestra interfaz IReservationService y la clase ReservationService.
Cree la interfaz IReservationService y agregue los siguientes métodos:
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);
}
}
Cree la clase ReservationService y reemplace su clase con el siguiente código que implementa todos los métodos:
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);
}
}
}
Este código es muy similar al código para la clase RestaurantService, pero para reservas en su lugar.
Agregándolas a la Inyección de Dependencias
El paso final para los servicios es agregarlos al contenedor de inyección de dependencias.
Dentro de Program.cs, agregue el siguiente código después del código que agregó allí anteriormente:
builder.Services.AddScoped<IRestaurantService, RestaurantService>();
builder.Services.AddScoped<IReservationService, ReservationService>();
Creando las vistas modelo
Antes de implementar el front end, necesitamos agregar las vistas modelo que actuarán como mensajero entre nuestro front y back end donde sea necesario. Incluso aunque nuestra aplicación es bastante simple, implementar el modelo de vista es una buena práctica ya que ayuda a desacoplar las piezas de la aplicación.
RestaurantListViewModel
La primera que agregaremos es el RestaurantListViewModel. Esto se usará como modelo en nuestra página Razor posteriormente para listar los restaurantes en nuestra base de datos.
-
Cree una nueva carpeta en la raíz del proyecto llamada ViewModels.
-
Agregue un nuevo archivo llamado RestaurantListViewModel.cs.
-
Agregue el siguiente código:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantListViewModel
{
public IEnumerable<Restaurant>? Restaurants { get; set; }
}
}
RestaurantAddViewModel
También queremos un modelo de vista que pueda ser usado por la vista de Agregar que agregaremos más tarde.
-
Dentro de la carpeta ViewModels, cree un nuevo archivo llamado RestaurantAddViewMode.cs.
-
Add:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantAddViewModel
{
public Restaurant? Restaurant { get; set; }
}
}
ReservationListViewModel
Ahora, queremos hacer algo muy similar para las reservas, empezando con ReservationListViewModel.
-
Cree un nuevo archivo en la carpeta ViewModels llamado ReservationListViewModel.cs.
-
Add:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationListViewModel
{
public IEnumerable<Reservation>? Reservations { get; set; }
}
}
ReservationAddViewModel
Finalmente, tenemos nuestro ReservationAddViewModel.
Cree el archivo y agregue este código:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationAddViewModel
{
public Reservation? Reservation { get; set; }
}
}
Adding to _ViewImports
Más adelante, agregaremos referencias a nuestros modelos y vistas modelo en las vistas. Para que la aplicación sepa qué son, necesitamos agregar referencias a ellos en el archivo _ViewImports.cshtml dentro de la carpeta Views.
Ya habrá algunas referencias allí, incluyendo TagHelpers, así que queremos agregar referencias a nuestras carpetas .Models y .ViewModels. Así que la parte superior del archivo debería parecerse a esto:
@using RestRes
@using RestRes.Models
@using RestRes.ViewModels
Creating the controllers
Now that we have the backend implementation and the view models we will refer to, we can start working toward the front end. We will be creating two controllers: one for Restaurant and one for Reservation.
RestaurantController
The first controller we will add is for the restaurant.
-
Dentro de la carpeta existente Controllers, agregue un archivo de controlador nuevo llamado RestaurantController.cs. Si estás usando Visual Studio, use el plantilla de controlador MVC – Controlador vacío.
-
Agregue este código:
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
Ahora, para el controlador de reservas. Esto es muy similar al Controlador de Restaurante, pero tiene una referencia tanto al restaurante como al servicio de reservas, ya que necesitamos asociar un restaurante con una reserva. Esto es porque en este momento, el proveedor EF Core no soporta relaciones entre entidades, así que podemos relacionar entidades de otra manera.
-
Cree otro archivo de controlador MVC vacío llamado ReservationController.cs.
-
Pegue el siguiente código:
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 las vistas
Ahora que tenemos el back end y los controladores preparados con los puntos finales para nuestro sistema de reservas de restaurante, es hora de implementar las vistas. Esto se hará usando las páginas de Razor. También verá referencias a clases de Bootstrap, ya que este es el framework CSS que viene con las aplicaciones MVC. Provee vistas para las operaciones CRUD tanto para listas como para reservas.
Listado de Restaurantes
Primero, proporcionaremos una vista que se mapeará a la raíz de /Restaurant, que por convención buscará en la función Index que implementamos.
ASP.NET Core MVC utiliza un patrón de convención en el cual se denomina al archivo .cshtml igual que el endpoint/método que utiliza y reside dentro de una carpeta nombrada según su controlador.
-
Dentro de la carpeta Views, cree una nueva subcarpeta llamada Restaurant.
-
Dentro de esa carpeta Restaurant, agregue una nueva vista creando un archivo llamado
Index.cshtml
. Si utiliza las plantillas disponibles, desea Vista de Razor – Vacío. Nombre la vista Index. -
Agregue este código:
@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>
Ahora vamos a actualizar la ruta predeterminada de Home a /Restaurant.
En Program.cs, dentro de app.MapControllerRoute
, reemplace la línea del patrón con lo siguiente:
pattern: "{controller=Restaurant}/{action=Index}/{id?}");
Si ejecutamos esto ahora, los botones dirigirían a 404s porque aún no los hemos implementado. Así que vamos a hacerlo ahora.
Agregando restaurantes
Empezaremos con el formulario para agregar nuevos restaurantes.
-
Agregue una nueva vista de Razor vacía dentro de la subcarpeta Restaurant llamada Add.cshtml.
-
Agregue el siguiente código:
@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>
Editar restaurantes
El código para la página de edición es casi idéntico a la de agregar, sin embargo, utiliza el restaurante como modelo ya que utilizará el restaurante que se le pase para pre-llenar el formulario para la edición.
-
Agregue otra vista dentro de la carpeta Restaurant llamada Edit.cshtml.
-
Agregue el siguiente código:
@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>
Eliminando restaurantes
La página final que necesitamos implementar es la página que se llama cuando se hace clic en el botón eliminar.
-
Cree una nueva vista vacía llamada Delete.cshtml.
-
Agregue el siguiente código:
@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>
Listando reservas
Hemos agregado las vistas para los restaurantes, así que ahora agregaremos las vistas para las reservas, comenzando por listar cualquier reserva existente.
-
Cree una nueva carpeta dentro de la carpeta Views llamada Reservation.
-
Cree un archivo de vista vacío llamado Index.cshtml.
-
Agregue el siguiente código para mostrar las reservas, si existen alguna:
@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>
}
Agregando reservas
Agregar reservas es el próximo paso.
-
Cree una vista vacía llamada Add.cshtml.
-
Agregue el siguiente código:
@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>
Editando reservas
Editando reservas es el próximo paso.
-
Cree una vista vacía llamada Edit.cshtml.
-
Agregue el siguiente código:
@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>
Eliminando reservas
Eliminando reservas es el próximo paso.
-
Cree una vista vacía llamada Delete.cshtml.
-
Agregue el siguiente código:
@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>
Actualizando NavBar
La última cosa que debemos agregar es actualizar la barra de navegación de la aplicación para que podamos cambiar fácilmente entre restaurantes y reservas.
Vaya al archivo ubicado en Views/Shared/_Layout.cshtml
. Busque el div
con la clase navbar-collapse
. Elimine toda esa sección y agregue el siguiente código:
<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>
Pruebando nuestra aplicación
Ahora tenemos una aplicación funcional que utiliza el nuevo proveedor MongoDB para EF Core. Ahora es el momento de probarlo todo y visitar nuestros puntos finales para asegurarnos de que todo funciona.
En el terminal ejecute el siguiente comando:
dotnet run
Pruebe a editar restaurantes y agregar reservas. Luego puede navegar a la página de la base de datos MongoDB Atlas y ver que sus cambios se reflejan en la base de datos.
Operaciones avanzadas de MongoDB: Búsqueda de Atlas y Búsqueda Vectorial
El proveedor de EF Core está construido sobre el Controlador de MongoDB en C#. Dado que ya tenemos acceso al MongoClient al crear el DbContext, esto nos permite realizar operaciones avanzadas de MongoDB como la Búsqueda de Atlas y la Búsqueda Vectorial. Estas características mejoran las capacidades de su aplicación al permitir funcionalidades de búsqueda poderosas mientras aún aprovecha el familiar framework EF Core.
Búsqueda de Atlas
La Búsqueda de Atlas es un motor de búsqueda de texto completo proporcionado por MongoDB Atlas. Permite ejecutar consultas de búsqueda sofisticadas en sus datos de MongoDB. Con la Búsqueda de Atlas, puede implementar características como autocompletado, búsqueda por categorías y ordenación basada en relevancia.
Para utilizar la Búsqueda de Atlas con el proveedor de EF Core, siga estos pasos:
-
Configurar índices en MongoDB Atlas:
-
Vaya a su clúster de MongoDB Atlas.
-
Vaya a la pestaña “Búsqueda” y cree un nuevo índice en su colección. Defina los campos que desea hacer buscables.
-
-
Define los Campos Buscables en sus Modelos: En sus modelos de C#, asegúrese de que los campos que desea buscar estén definidos correctamente. Aquí hay un ejemplo de la definición de un modelo de Producto.
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; } }
-
Ejecución de consultas de búsqueda: Utilizar las capacidades del conductor .NET de MongoDB para realizar búsquedas de texto. Dado que EF Core en sí no admite directamente el símbolo de búsqueda específico de MongoDB, tendrá que utilizar el conductor en conjunto con EF Core. Aquí tienes un ejemplo:
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
("Products"); var searchResult = collection.Aggregate() .Match(Builders .Filter.Text("search term")) .ToList();
Este ejemplo muestra cómo realizar una búsqueda de texto en la colección Products
. El filtro Text
ayuda a buscar a través de todos los campos indexados definidos en tu índice de búsqueda de Atlas Search.
Búsqueda Vectorial
La búsqueda vectorial en MongoDB se utiliza para buscar documentos basándonos en las similitudes de vectores, lo que es particularmente útil para aplicaciones que involucran aprendizaje automático, recomendaciones y procesamiento del lenguaje natural. La búsqueda vectorial permite consultar documentos utilizando vectores que representan texto, imágenes u otros datos de alta dimensión.
-
Crear y almacenar vectores: Primero, asegúrese de que sus documentos contengan vectores. Tal vez necesite preprocesar sus datos para generar estos vectores utilizando modelos de aprendizaje automático.
-
Indexar vectores en MongoDB Atlas: Cree un índice especial en el campo vectorial de MongoDB Atlas para permitir búsquedas de similitud de vectores eficientes.
-
Realización de Búsquedas Vectoriales: Utilice el Controlador de MongoDB para .NET para consultar basado en similitud de vectores.
Integración con EF Core
Si bien el Proveedor de MongoDB para EF Core simplifica las operaciones CRUD, algunas características avanzadas como la Búsqueda de Atlas y la Búsqueda Vectorial requieren el uso directo del Controlador de MongoDB para .NET. Sin embargo, aún puede integrar estas operaciones en su aplicación basada en EF Core utilizando el controlador para funcionalidades de búsqueda y EF Core para otras tareas de gestión de datos.
Al combinar EF Core y las características avanzadas de MongoDB, puede construir aplicaciones potentes y flexibles que aprovechan lo mejor de ambos mundos: los patrones de acceso a datos estructurados de EF Core y las capacidades de búsqueda poderosas de MongoDB Atlas.
Source:
https://www.freecodecamp.org/news/using-entity-framework-core-with-mongodb/