O Entity Framework Core é um popular ORM (Object-Relational Mapper) para aplicações .NET, que permite que os desenvolvedores trabalhem com bancos de dados usando objetos .NET. Ele pode ser usado com muitos tipos de bancos de dados, incluindo o MongoDB.
Neste artigo, você vai aprender como usar o Entity Framework Core com o MongoDB. Este artigo cobre os fundamentos, explica os benefícios e fornece um tutorial passo a passo. Se você for novo no MongoDB ou no Entity Framework Core, ou apenas procurando integrar essas ferramentas em seus projetos .NET, este guia o ajudará a atingir o gap entre bancos de dados relacionais e NoSQL.
O artigo começa com uma breve Introdução ao MongoDB bem como uma Introdução ao Entity Framework Core da Microsoft. Em seguida, ele cobre como usar o provedor MongoDB EF Core. Depois de passar por detalhes técnicos com alguns exemplos básicos, você criará um projeto completo com MongoB e Entity Framework Core para ver como tudo funciona juntos. O projeto usará dados de exemplo do MongoDB Atlas para criar um sistema de reservas de Restaurante.
Há também uma versão de vídeo deste artigo que você pode assistir no canal do YouTube freeCodeCamp.org.
Introdução ao MongoDB
O MongoDB é um popular banco de dados NoSQL projetado para lidar com grandes volumes de dados e fornecer alta performance, escalabilidade e flexibilidade. Ao contrário dos bancos de dados relacionais tradicionais, o MongoDB armazena dados em documentos flexíveis, semelhantes a JSON. Este paradigma de documentos orientados permite o armazenamento de estruturas de dados complexas de uma maneira mais natural e intuitiva.
No MongoDB, dados são armazenados em coleções, que são semelhantes a tabelas em bancos de dados relacionais mas sem um esquema fixo. Isto significa que você pode ter documentos com estruturas diferentes na mesma coleção. Esta flexibilidade é uma das principais vantagens de usar o MongoDB, especialmente quando se trata de dados não estruturados ou semi-estruturados.
Vamos olhar para um exemplo de documento MongoDB. Imagine que temos uma coleção chamada users
que armazena informações sobre usuários em uma aplicação. Aqui é o que um documento típico pode parecer:
{
"_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"]
}
Neste documento, temos vários campos como name
, email
, age
, e address
. O campo address
em si é um documento aninhado que contém vários subcampos como street
, city
, state
, e zip
. Adicionalmente, o campo hobbies
é um array de strings.
Enquanto isso parece JSON, o MongoDB armazena dados em um formato binário chamado BSON (Binary JSON). O BSON extende o modelo JSON para fornecer tipos de dados adicionais, como inteiros, flutuantes, datas e dados binários. Este formato binário é otimizado para performance e flexibilidade, permitindo que o MongoDB armazene e recupere dados com eficiência.
Uma outra funcionalidade importante do MongoDB é sua capacidade de dimensionar horizontalmente. Isso significa que você pode distribuir seus dados entre vários servidores, fazendo com que seja mais fácil gerenciar grandes conjuntos de dados e garantir alta disponibilidade. O MongoDB também suporta consultas abrangentes, indexação e agregação, tornando-se uma ferramenta poderosa para uma ampla gama de aplicações.
Por exemplo, você pode executar uma consulta para encontrar todos os usuários que moram em uma cidade específica:
db.users.find({ "address.city": "Anytown" })
Você pode encontrar usuários que têm um interesse específico:
db.users.find({ "hobbies": "coding" })
O MongoDB é amplamente usado em várias indústrias,从电子商务 e gerenciamento de conteúdo até análise em tempo real e aplicações de Internet das Coisas (IoT). Sua flexibilidade e escalabilidade o tornam uma escolha excelente para aplicações modernas que precisam lidar com dados diversos e dinâmicos.
Agora que nós temos um entendimento básico do que é o MongoDB e por que é popular, vamos passar para outra ferramenta essencial na nossa stack tecnológica: o Entity Framework Core da Microsoft.
Introdução ao Entity Framework Core da Microsoft
O Entity Framework Core, frequentemente abreviado como EF Core, é um moderno objeto-mapeamento de banco de dados para .NET. Ele permite que desenvolvedores trabalhem com um banco de dados usando objetos .NET, eliminando a necessidade de escrever a maioria do código de acesso a dados que os desenvolvedores normalmente precisam escrever.
O EF Core é uma versão leve, extensível e multiplataforma da popular tecnologia de acesso a dados Entity Framework (EF). Ele suporta uma variedade de motores de banco de dados, incluindo SQL Server, SQLite e MongoDB.
Um dos principais benefícios de usar EF Core é que ele permite que desenvolvedores trabalhem com dados de uma maneira mais intuitiva e orientada a objetos. Em vez de escrever consultas SQL brutas, você pode interagir com seu banco de dados usando LINQ (Language Integrated Query) e classes fortemente tipadas.
Vamos olhar por um exemplo básico. Imagine que temos uma classe Product
:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Isso é muito simples com apenas três campos. Usando o EF Core, você pode criar uma classe de contexto que representa uma sessão com o banco de dados e inclui um DbSet
para cada tipo de entidade que você quer consultar ou salvar:
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 uma classe chamada AppDbContext
que herda da classe DbContext
do Entity Framework Core. Esta classe é usada para interagir com o banco de dados. Dentro desta classe, há uma propriedade DbSet<Product>
chamada Products
, que representa uma coleção de entidades Product
e corresponde a uma tabela chamada Products
no banco de dados. O método OnConfiguring
é sobrescrito para configurar a conexão com o banco de dados, você pode especificar vários bancos de dados como provedor de banco de dados. O método usa um optionsBuilder
para configurar a conexão com um marcador de posição para a string de conexão de banco de dados real. Evidentemente, essa string de conexão deve ser substituída pela verdadeira contendo os detalhes necessários para se conectar ao banco de dados. Quando você cria uma instância de AppDbContext
na aplicação, ela usa essa configuração para realizar operações como consultar ou salvar entidades Product
na tabela Products
.
Com este setup, você pode realizar operações CRUD (Criar, Ler, Atualizar, Excluir) usando o EF Core. Por exemplo, para adicionar um novo produto ao banco de dados, você pode usar 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 demonstra como adicionar um novo produto à base de dados usando Entity Framework Core. Uma instância de AppDbContext
é criada, e dentro deste contexto, um novo objeto Product
com o nome “Laptop” e o preço de 999.99 é instanciado. Este novo produto é então adicionado à coleção Products
gerenciada pelo AppDbContext
. Finalmente, o método SaveChanges
é chamado para salvar as mudanças na base de dados, efetivamente inserindo o novo produto na tabela Products
.
Para consultar produtos, você pode usar 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 demonstra como consultar a base de dados usando Entity Framework Core. Uma instância de AppDbContext
é criada, e dentro deste contexto, é feita uma consulta para recuperar todos os produtos com um preço maior que 500. Os resultados são armazenados em uma lista chamada products
. Em seguida, um loop percorre cada produto na lista, imprimindo o nome e o preço de cada produto no console.
EF Core cuida de traduzir essas consultas LINQ em comandos SQL apropriados para sua base de dados, tornando a acesso a dados simples e manutenível.
EF Core também suporta recursos avançados como o gerenciamento de mudanças, carregamento em tempo de execução e migrações, o que ajuda a gerenciar mudanças no esquema da base de dados ao longo do tempo.
Em resumo, EF Core é uma poderosa ORM que simplifica o acesso a dados em aplicações .NET, permitindo que você trabalhe com seus dados usando objetos .NET e LINQ. Seu suporte a vários motores de base de dados e sua extensibilidade o tornam uma escolha versátil para uma ampla gama de aplicações.
Aqui, veremos como o provedor MongoDB EF Core atua de ponte entre o MongoDB e o EF Core, permitindo que usemos os padrões familiares do EF Core com um banco de dados MongoDB.
Como o Provedor MongoDB EF Core Atua de Ponte
O Provedor MongoDB Entity Framework Core (EF Core) é uma ferramenta que permite que os desenvolvedores use o MongoDB com o Entity Framework Core (EF Core), combinando a flexibilidade do MongoDB com os padrões de API e de projeto familiares do EF Core. Este provedor permite que você trabalhe com o MongoDB usando as mesmas técnicas de primeiro código e consultas LINQ que você usaria com bancos de dados relacionais, otimizando o desenvolvimento e reduzindo a curva de aprendizagem para aqueles que estão familiarizados com o EF Core.
O Provedor MongoDB EF Core atua de ponte entre o MongoDB e o EF Core ao suportar operações básicas de CRUD, consultas LINQ e documentos aninhados, entre outras funcionalidades. Aqui estão algumas capacidades chave:
-
Fluxos de Trabalho de Primeiro Código: Você pode definir seus modelos de dados em C# e usar o EF Core para gerar o esquema do MongoDB, em vez de começar com o esquema do banco de dados e gerar código a partir dele. Isso é particularmente útil para desenvolvedores que preferem gerenciar sua estrutura de banco de dados através de código.
-
Operações CRUD: O provedor suporta operações básicas de criação, leitura, atualização e exclusão. Por exemplo, você pode adicionar um novo registro ao banco de dados usando o mesmo código que vimos anteriormente:
; }
-
Suporte a Consultas LINQ: Você pode usar LINQ para realizar consultas contra o MongoDB, permitindo que você aproveite seu conhecimento existente sobre C# e .NET para interagir com o banco de dados.
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}"); } }
-
Rastreamento de Alterações: As capacidades de rastreamento de alterações do EF Core são suportadas, permitindo o reconhecimento automático e a gravação de alterações feitas em suas entidades de dados.
-
Documentos Embedidos: O provedor suporta documentos embutidos, permitindo que você armazene dados relacionados dentro de um único documento, o que é um padrão comum no MongoDB.
-
Mapeamento de Classes e Serialização: As suas classes C# são mapeadas para coleções do MongoDB, com suporte para vários tipos de dados e configurações de serialização para garantir que dados são armazenados corretamente.
Modelagem de Dados e Operações CRUD Utilizando o MongoDB Atlas
Agora vamos passar por um exemplo rápido sobre como usar o provedor MongoDB EF Core. Mas em breve, vamos criar um projeto completo no Visual Studio Code para que você veja tudo em contexto.
Nesta seção, exploraremos como definir modelos de dados e realizar operações CRUD (Criar, Ler, Atualizar, Excluir) usando o provedor MongoDB Entity Framework Core (EF) com o MongoDB Atlas. Esta integração permite que você leverage a flexibilidade do MongoDB com os padrões familiares do EF Core.
Configurando seu Ambiente
Para começar, você precisa adicionar as pacotes NuGet necessários ao seu projeto:
dotnet add package MongoDB.EntityFrameworkCore
O pacote MS EF Core e o driver MongoDB em C# são adicionados como dependências quando você adiciona o pacote de provedor MongoDB EF Core. Estes pacotes permitem que sua aplicação interaja com o MongoDB através do EF Core, usando as mesmas definições de contexto e entidades que você usaria com um banco de dados relacional.
Configurando o MongoDB Atlas
Antes de você poder realizar operações CRUD, você precisa configurar um cluster MongoDB Atlas e conectar sua aplicação a ele.
Aqui estão as etapas. Note que vamos passar sobre estes detalhes quando criarmos o projeto em breve.
-
Criar uma Conta MongoDB Atlas: Crie uma conta gratuita em MongoDB Atlas.
-
Criar um Cluster: Configure um novo cluster. O MongoDB Atlas oferece um nível grátis perfeito para desenvolvimento e aplicações de pequeno porte.
-
Obter String de Conexão: Obtenha sua string de conexão do painel do MongoDB Atlas. Ela parecerá algo como isto:
mongodb+srv://<username>:<password>@cluster0.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
Modelando os Dados
Defina uma classe para usar como modelo para sua entidade. Para este exemplo, vamos criar uma classe Cliente
:
public class Customer
{
public ObjectId Id { get; set; }
public String Name { get; set; }
public String Order { get; set; }
}
Esta classe Cliente
representa a estrutura dos documentos armazenados na coleção MongoDB.
Criar uma Classe de Contexto de BD
Para começar a usar o Entity Framework Core, crie uma classe de contexto que herde de DBContext. A instância da classe derivada DbContext
representa uma sessão de banco de dados e é usada para consultar e salvar instâncias das suas entidades.
A classe DBContext
expõe propriedades DBSet
que especificam as entidades com as quais você pode interagir enquanto usa esse contexto.
Este exemplo cria uma instância de uma classe derivada de DBContext
e especifica o objeto Customer
como uma propriedade 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");
}
}
Fluxo de Trabalho Primeiro-Código
Com o provedor MongoDB EF, você pode usar um fluxo de trabalho primeiro-código. Isso significa que você define suas classes primeiro, e o EF Core gerenciará a criação e o gerenciamento do esquema subjacente do MongoDB. Isso é particularmente útil para o MongoDB, que não impõe um esquema, permitindo estruturas de dados flexíveis e dinâmicas.
Usar MongoDB
Uma vez que temos criado uma classe DBContext
, precisamos construir um objeto DbContextOptionsBuilder
e chamar seu método UseMongoDB()
. Este método aceita dois parâmetros: uma instância de MongoClient
e o nome do banco de dados que armazena as coleções com as quais você está trabalhando.
O método UseMongoDB()
retorna um objeto DbContextOptions
. Passar a propriedade Options
the este objeto para o construtor da sua 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);
Operações CRUD
Agora vamos ver como codificar as operações CRUD. Vamos se concentrar em cada operação individualmente.
Operação de Criação
Para criar um novo documento no MongoDB, você usa o método Add
na DbSet
e chama SaveChanges
. Este é um exemplo de como criar um novo 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 cria uma nova instância de Customer
e adiciona-a à coleção Customers
. O método SaveChanges
salva o novo cliente no banco de dados MongoDB.
Leitura de Operação
Para ler documentos da coleção MongoDB, você pode usar consultas LINQ no DbSet
. Este é um exemplo de como recuperar todos os 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 recupera todos os clientes da coleção Customers
e imprime seus detalhes.
Operação de Atualização
Para atualizar um documento existente, você recupera o documento, modifica suas propriedades e chama SaveChanges
. Este é um exemplo de atualizar uma ordem de 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 encontra o cliente chamado “Beau Carnes” e atualiza sua ordem para “Smartphone”.
Operação de Exclusão
Para excluir um documento, você recupera o documento, remove-o do DbSet
e chama SaveChanges
. Este é um exemplo de excluir um 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 encontra o cliente chamado “Beau Carnes” e o exclui da coleção Customers
.
Rastreamento de Mudança
As capacidades de rastreamento de mudança do EF Core são totalmente suportadas, permitindo atualizações eficientes de documentos. Quando você modifica uma entidade e chama SaveChanges
, o EF Core gerará as comandos MongoDB necessários para atualizar somente os campos alterados.
Usando o provedor MongoDB EF, você pode integrar com facilidade o modelo de documento flexível do MongoDB com as capacidades robustas de ORM do EF Core, oferecendo uma potente ferramenta para os desenvolvedores .NET construírem aplicações modernas.
Tutorial
Agora vamos juntar tudo isso e criar um sistema de reservas de restaurantes.
Pré-requisitos
Para acompanhar este tutorial, você vai precisar de algumas coisas:
-
.NET 7.0.
-
Conhecimento básico de ASP.NET MVC e C#.
-
Conta grátis do MongoDB Atlas e cluster gratuito da camada grátis.
Crie o projeto
O ASP.NET Core é um framework web muito flexível, permitindo que você crie diferentes tipos de aplicações web que têm pequenas diferenças em termos de UI ou estrutura. Para este tutorial, vamos criar um projeto MVC que fará uso de arquivos estáticos e controladores. Existem outros tipos de interface que você pode usar, como o React, mas o MVC com visões .cshtml é o mais comumente usado. Para criar o projeto, vamos usar o CLI do .NET:
dotnet new mvc -o RestRes
Como usamos o CLI, embora seja mais fácil, ele apenas cria o arquivo csproj e não o arquivo de solução, que nos permite abri-lo no Visual Studio, então vamos corrigir isso.
cd RestRes
dotnet new sln
dotnet sln .\RestRes.sln add .\RestRes.csproj
Adicione os pacotes NuGet
Agora que temos o novo projeto criado, vamos adicionar os pacotes NuGet necessários. Usando o Gerenciador de Pacotes NuGet ou usando o comando abaixo do CLI do .NET, adicione o pacote MongoDB MongoDB.EntityFrameworkCore.
dotnet add package MongoDB.EntityFrameworkCore
Crie os modelos
Antes de começarmos a implementar os novos pacotes que acabamos de adicionar, precisamos criar as modelos que representam as entidades que queremos no nosso sistema de reserva de restaurantes, que serão armazenados obviamente em MongoDB Atlas como documentos. Nas seções seguintes, criaremos os seguintes modelos:
-
Restaurante
-
Reserva
-
ConfiguraçõesMongoDB
Restaurante
A primeira coisa que precisamos fazer é criar o nosso modelo de restaurante que representará os restaurantes disponíveis para reserva no nosso sistema.
-
Crie um novo arquivo na pasta Models chamada Restaurant.cs.
-
Adicione o seguinte 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; }
}
}
O atributo de coleção antes da classe informa à aplicação qual coleção do banco de dados estamos usando. Isso permite que tenhamos nomes diferentes ou maiúsculas e minúsculas entre nossa classe e nossa coleção, caso queira.
Reserva
Também precisamos criar uma classe de reserva para representar qualquer reserva que fizermos no nosso sistema.
-
Crie um novo arquivo na pasta Models chamado Reservation.cs.
-
Adicione o seguinte código a ele:
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; }
}
}
ConfiguraçõesMongoDB
Embora não seja um documento na nossa base de dados, precisamos de uma classe de modelo para armazenar as configurações relacionadas ao MongoDB para que elas possam ser usadas em toda a aplicação.
-
Crie outro arquivo em Models chamado MongoDBSettings.cs.
-
Adicione o seguinte código:
namespace RestRes.Models
{
public class MongoDBSettings
{
public string AtlasURI { get; set; }
public string DatabaseName { get; set; }
}
}
Configurando o EF Core
Aqui chegamos à parte interessante. Vamos começar a implementar o EF Core e aproveitar o novo provedor MongoDB. Se você já está familiarizado com o EF Core, parte deste processo pode parecer-se com o que você já conhece.
RestaurantReservationDbContext
-
Crie uma pasta chamada Services, e crie um arquivo chamado RestaurantReservationDbContext.cs.
-
Substitua o código dentro do namespace pelo seguinte:
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 você está familiarizado com o EF Core, isso parecerá familiar. A classe extende o DbContext e criamos propriedades DbSet que armazenam os modelos que também estarão presentes na base de dados. Também sobrescrevemos o método OnModelCreating. Você pode notar que, ao contrário do uso com o SQL Server, nós não chamamos .ToTable(). Podíamos chamar ToCollection em vez disso, mas isso não é necessário aqui, já que especificamos a coleção usando atributos nas classes.
Adicione a string de conexão e os detalhes do banco de dados à appsettings
Anteriormente, criamos um modelo de MongoDBSettings e agora precisamos adicionar os valores que as propriedades mapeadas para nossos appsettings.
-
Ambos appsettings.json e appsettings.Development.json, adicione o seguinte novo secção:
"MongoDBSettings": { "AtlasURI": "mongodb+srv://<username>:<password>@<url>", "DatabaseName": "restaurants" }
-
Substitua a URI do Atlas com a sua própria string de conexão do Atlas.
Atualizando o program.cs
Agora que configuramos nossos modelos e DbContext, é hora de adicioná-los ao nosso arquivo program.cs.
Após a linha existente builder.Services
.AddControllersWithViews();
, adicione o seguinte 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 ?? ""));
Criando os serviços
Agora, é hora de adicionar os serviços que usaremos para se comunicar com o banco de dados através do RestaurantBookingDbContext que criamos. Para cada serviço, criaremos uma interface e a classe que a implementa.
IRestaurantService e RestaurantService
A primeira interface e serviço que implementaremos é para executar as operações CRUD na coleção de restaurantes. Este é conhecido como o padrão de repositório. Podem ver pessoas interagindo com o DbContext diretamente. Mas a maioria das pessoas usa este padrão, por isso incluímos aqui.
-
Se você ainda não criou, crie uma pasta Services para armazenar nossas novas classes.
-
Crie uma interface IRestaurantService e adicione o seguinte código para os 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);
}
}
-
Crie um arquivo de classe RestaurantService.
-
Atualize a declaração da classe RestaurantService para que ela implemente a interface IRestaurantService que acabamos de criar:
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
A seguir, está o nossso IReservationService e ReservationService.
Crie a interface IReservationService e adicione os seguintes 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);
}
}
Crie a classe ReservationService e substitua sua classe pelo código seguinte que implementa todos os 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);
}
}
}
Esse código é muito semelhante ao código para a classe RestaurantService, mas para reservas em vez disso.
Adicionando-os ao Injeção de Dependência
A etapa final para os serviços é adicioná-los ao container de injeção de dependências.
No interior do arquivo Program.cs, adicione o código a seguir após o código que já adicionamos aí anteriormente:
builder.Services.AddScoped<IRestaurantService, RestaurantService>();
builder.Services.AddScoped<IReservationService, ReservationService>();
Criando os modelos de visualização
Antes de implementarmos o front-end, precisamos adicionar os modelos de visualização que servirão de mensageiro entre nossos fronts e backends onde necessário. Mesmo que nossa aplicação seja relativamente simples, implementar o modelo de visualização é ainda uma boa prática, já que ajuda a desacoplar as partes do aplicativo.
RestaurantListViewModel
O primeiro que vamos adicionar é o RestaurantListViewModel. Isso será usado como o modelo em nossa página Razor posteriormente para listar restaurantes em nossa base de dados.
-
Crie um novo diretório no root do projeto chamado ViewModels.
-
Adicione um novo arquivo chamado RestaurantListViewModel.cs.
-
Adicione o seguinte código:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantListViewModel
{
public IEnumerable<Restaurant>? Restaurants { get; set; }
}
}
RestaurantAddViewModel
Nós também queremos um modelo de visualização que possa ser usado pela view Add que adicionaremos depois.
-
No diretório ViewModels, crie um novo arquivo chamado RestaurantAddViewModel.cs.
-
Add:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantAddViewModel
{
public Restaurant? Restaurant { get; set; }
}
}
ReservationListViewModel
Agora, queremos fazer algo muito semelhante para as reservas, começando com ReservationListViewModel.
-
Crie um novo arquivo na pasta ViewModels chamado ReservationListViewModel.cs.
-
Add:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationListViewModel
{
public IEnumerable<Reservation>? Reservations { get; set; }
}
}
ReservationAddViewModel
Finalmente, temos nosso ReservationAddViewModel.
Crie o arquivo e adicione este código:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationAddViewModel
{
public Reservation? Reservation { get; set; }
}
}
Adding to _ViewImports
Mais tarde, nós vamos adicionar referências aos nossos modelos e viewmodels nas views. Para a aplicação saber o que eles são, nós precisamos adicionar referências a eles no arquivo _ViewImports.cshtml dentro da pasta Views.
Já haverá algumas referências aí, incluindo TagHelpers, então nós queremos adicionar referências para nossas pastas .Models e .ViewModels. Então o topo do arquivo deveria parecer com isto:
@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 da pasta existente de Controllers, adicione um novo arquivo de controlador chamado RestaurantController.cs. Se estiver usando o Visual Studio, use o modelo de controlador MVC – Controlador vazio.
-
Adicione 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
Agora para o controlador de reservas. Isso é muito semelhante ao RestaurantController, mas ele tem uma referência a ambos o serviço de restaurante e reserva, pois precisamos associar um restaurante a uma reserva. Isso é porque, no momento, o provedor EF Core não suporta relacionamentos entre entidades, portanto, podemos relacionar entidades de uma maneira diferente.
-
Crie outro arquivo de controlador MVC vazio chamado ReservationController.cs.
-
Copie o seguinte 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);
}
}
}
Criando as visualizações
Agora que temos o back-end e os controladores preparados com os pontos de extremidade para o nosso sistema de reserva de restaurantes, é hora de implementar as visualizações. Isto será feito usando páginas Razor. Você também verá referências a classes de Bootstrap, pois é a framework CSS que vem com as aplicações MVC. Vamos fornecer visualizações para as operações CRUD de ambas as listagens e agendamentos.
Listando os restaurantes
Primeiro, vamos fornecer uma visualização que será mapeada para a raiz de /Restaurante, que de acordo com a convenção, olhará para o método Index que implementamos.
ASP.NET Core MVC usa um padrão de convenção onde você nomeia o arquivo .cshtml com o nome do ponto final/método que ele usa e vive dentro de uma pasta com o nome de seu controlador.
-
Dentro da pasta Views, crie uma nova subpasta chamada Restaurant.
-
Nessa pasta Restaurant, adicione uma nova visualização criando um arquivo chamado
Index.cshtml
. Se usar as templates disponíveis, você quer Visualização Razor – Vazio. Nomeie a visualização Index. -
Adicione 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>
Agora vamos atualizar a rota padrão de Home para /Restaurant.
No Program.cs, dentro de app.MapControllerRoute
, substitua a linha do padrão por o seguinte:
pattern: "{controller=Restaurant}/{action=Index}/{id?}");
Se executássemos isso agora, os botões levariam a 404s porque ainda não implementamos. Então vamos fazer isso agora.
Adicionando restaurantes
Vamos começar com o formulário para adicionar novos restaurantes.
-
Adicione um novo, vazio Visualização Razor dentro da subpasta Restaurant chamada Add.cshtml.
-
Adicione o seguinte 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>
Editando restaurantes
O código para a página Editar é quase idêntico ao Adicionar, mas usa o Restaurante como modelo, pois usará o restaurante que lhe for passado para pré-preencher o formulário para edição.
-
Adicione outra visualização dentro da subpasta Restaurante chamada Editar.cshtml.
-
Adicione o seguinte 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>
Eliminar restaurantes
A página final que precisamos implementar é a página que é chamada quando o botão excluir é clicado.
-
Crie uma nova View vazia chamada Excluir.cshtml.
-
Adicione o seguinte 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
Adicionamos as views para os restaurantes, então agora vamos adicionar as views para as reservas, começando por listar quaisquer reservas existentes.
-
Crie uma nova pasta dentro da pasta Views chamada Reservation.
-
Crie um novo arquivo de visualização vazio chamado Index.cshtml.
-
Adicione o seguinte código para exibir as reservas, se houver alguma:
@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>
}
Adicionando reservas
Adicionando reservas é a próxima coisa.
-
Crie uma visão vazia chamada Add.cshtml.
-
Adicione o seguinte 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
A próxima coisa é editar reservas.
-
Crie uma visão vazia chamada Edit.cshtml.
-
Adicione o seguinte 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>
Excluindo reservas
A próxima coisa é excluir reservas.
-
Crie uma visão vazia chamada Delete.cshtml.
-
Adicione o seguinte 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>
Atualizando NavBar
A coisa final a ser adicionada é atualizar a barra de navegação do aplicativo para que possamos facilmente alternar entre restaurantes e reservas.
Navegue até o arquivo em Views/Shared/_Layout.cshtml
. Encontre o div
com a classe navbar-collapse
. Remova toda essa seção e adicione o seguinte 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>
Testando o nosso aplicativo
Agora temos um aplicativo funcional que usa o novo provedor MongoDB para EF Core. Agora é a hora de testá-lo tudo e visitar nossos endpoints para ter certeza de que tudo funciona.
No terminal, execute o seguinte comando:
dotnet run
Tente editar restaurantes e adicionar reservas. Em seguida, você pode navegar até a página da base de dados MongoDB Atlas e ver que suas mudanças são refletidas na base de dados.
Operações Avançadas do MongoDB: Pesquisa Atlas e Pesquisa Vetorial
O provedor do EF Core está construído em cima do driver MongoDB C#. Como já tem acesso ao MongoClient ao criar o DbContext, isso permite que você execute operações avançadas do MongoDB, como Pesquisa Atlas e Pesquisa Vetorial. Essas funcionalidades aprimoram as capacidades de sua aplicação, permitindo funcionalidades de busca poderosas enquanto ainda aproveita o familiar framework EF Core.
Pesquisa Atlas
A Pesquisa Atlas é um motor de busca de texto completo fornecido pelo MongoDB Atlas. Permite que você execute consultas de busca sofisticadas em seus dados do MongoDB. Com a Pesquisa Atlas, você pode implementar recursos como autocomplete, busca com facetas e classificação baseada na relevância.
Para usar a Pesquisa Atlas com o provedor do EF Core, siga estes passos:
-
Configurar índices no MongoDB Atlas:
-
Vá até o cluster MongoDB Atlas.
-
Navegue até a aba “Pesquisa” e crie um novo índice na sua coleção. Defina os campos que você quer tornar pesquisáveis.
-
-
Defina Campos Pesquisáveis em Seus Modelos: Em seus modelos em C#, certifique-se de que os campos que você deseja pesquisar estejam corretamente definidos. Aqui está um exemplo de definição de um modelo de Produto.
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; } }
-
Realizando Buscas de Consultas: Use as capacidades do driver MongoDB .NET para realizar buscas de texto. Como o EF Core por si mesmo não suporta diretamente a sintaxe de busca específica do MongoDB, você precisará usar o driver em conjunto com o EF Core. Aqui está um exemplo:
using MongoDB.Driver; using MongoDB.Driver.Linq; var client = new MongoClient("sua-string-de-conexão-mongodb"); var database = client.GetDatabase("nome-do-seu-banco-de-dados"); var collection = database.GetCollection<Product>("Products"); var searchResult = collection.Aggregate() .Match(Builders<Product>.Filter.Text("termo-de-busca")) .ToList();
Este exemplo mostra como executar uma pesquisa de texto na coleção Products
. O filtro Text
ajuda a procurar através de todos os campos indexados definidos no seu índice de pesquisa do Atlas Search.
Pesquisa Vetorial
A Pesquisa Vetorial no MongoDB é usada para procurar documentos com base em similaridades vetoriais, o que é particularmente útil para aplicações envolvendo aprendizado de máquina, recomendações e processamento natural de linguagem. A Pesquisa Vetorial permite que você realize consultas usando vetores que representam texto, imagens ou outos dados de alta dimensão.
-
Criar e Armazenar Vetores: Primeiro, certifique-se que seus documentos contêm vetores. Você pode precisar pré-processar seus dados para gerar esses vetores usando modelos de aprendizado de máquina.>
-
Indexar Vetores no MongoDB Atlas: Crie um índice especial no campo vetorial no MongoDB Atlas para permitir pesquisas de similaridade de vetores eficientes.
-
Executando Pesquisas Vetoriais: Use o Driver MongoDB .NET para consultar com base na similaridade vetorial.
Integrando com EF Core
Enquanto o provedor MongoDB EF Core simplifica as operações CRUD, algumas funcionalidades avançadas como a Pesquisa Atlas e a Pesquisa Vetorial exigem o uso direto do Driver MongoDB .NET. No entanto, você ainda pode integrar essas operações dentro de sua aplicação baseada em EF Core usando o driver para funcionalidades de busca e EF Core para outras tarefas de gerenciamento de dados.
Ao combinar EF Core e as funcionalidades avançadas do MongoDB, você pode construir aplicações poderosas e flexíveis que aproveitam o melhor de ambos mundos – os padrões de acesso a dados estruturados do EF Core e as poderosas capacidades de busca do MongoDB Atlas.
Source:
https://www.freecodecamp.org/news/using-entity-framework-core-with-mongodb/