Объектно-relationalного Mapper) для приложений .NET, позволяющий разработчикам работать с базами данных, используя объекты .NET. Он может использоваться с многими типами баз данных, включая MongoDB.
В этой статье вы узнаете, как использовать Entity Framework Core с MongoDB. Эта статья охватывает базовые понятия, объясняет преимущества и показывает Шаг за шагом руководство. Независимо от того, являетесь ли вы новичком в MongoDB или Entity Framework Core, или просто хотите интегрировать эти инструменты в ваши проекты .NET, этот指南 поможет вам架起关系型和非关系型 базы данных之间的桥梁.
Статья начинается с короткого введения в MongoDB, а также введения в Entity Framework Core компании Microsoft. Затем она охватывает использование MongoDB EF Core Provider. После прохождения технических деталей с несколькими базовыми примерами вы создадите полный проект с MongoB и Entity Framework Core, чтобы увидеть, как все соединено вместе. Проект будет использовать для создания системы бронирования ресторанов образцы данных MongoDB Atlas.
Также есть видеоверсия этой статьи, которую вы можете посмотреть на YouTube-канале freeCodeCamp.org.
Введение в MongoDB
MongoDB – это популярная NoSQL-база данных, проектированная для обработки больших объемов данных и обеспечения высокой производительности, масштабности и гибкости. Unlike traditional relational databases, MongoDB stores data in flexible, JSON-like documents. This document-oriented approach allows for the storage of complex data structures in a more natural and intuitive way.
В MongoDB данные сохраняются в коллекциях, которые сходны с таблицами в реляционных базах данных, но не имеют фиксированного схемы. Это意味着 можете иметь документы с различными структурами в同一 коллекции. Эта гибкость является одним из ключевых преимуществ использования MongoDB, особенно при работе с неструктурированными или полуструктурированными данными.
Давайте посмотрим на пример документа MongoDB. предположим, у нас есть коллекция, названная users
, которая содержит информацию о пользователях в приложении. Вот, какого типичного документа может быть:
{
"_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"]
}
В этом документе есть различные поля, такие как name
, email
, age
и address
. поле address
само по себе является вложенным документом, содержащим множество подполей, таких как street
, city
, state
и zip
. Кроме того, поле hobbies
является массивом строк.
хотя это выглядит как JSON, MongoDB сохраняет данные в бинарном формате, называемом BSON (бинарный JSON). BSON расширяет модель JSON, чтобы обеспечить дополнительные типы данных, такие как целые числа,浮点数, даты и бинарные данные. Этот бинарный формат оптимизирован для производительности и гибкости, что позволяет MongoDB эффективно хранить и извлекать данные.
Другая важная особенность MongoDB – ее способность распределять данные горизонтально. Это意味着 можете распределить ваши данные по нескольким серверам, что упрощает управление большими наборами данных и обеспечивает высокую доступность. MongoDB также поддерживает богатые запросы, индексацию и агрегирование, делая ее мощным инструментом для широкого круга приложений.
например, можно выполнять запрос, чтобы найти всех пользователей, которые проживают в определенном городе:
db.users.find({ "address.city": "Anytown" })
Вы можете найти пользователей, у которых есть определенная увлеченность:
db.users.find({ "hobbies": "coding" })
MongoDB широко используется во многих отраслях, от электронной коммерции и управления контентом до реального временного анализа и приложений Internet of Things (IoT). Ее гибкость и skalability делают ее отличным выбором для современных приложений, которым нужно обрабатывать различные и динамические данные.
Теперь, когда мы приобрели базовое понимание того, что такое MongoDB и почему она популярна, далее мы перейдем к другому необходимому инструменту в нашей технологической платформе: Microsoft Entity Framework Core.
Интро в Microsoft Entity Framework Core
Entity Framework Core, часто сокращаемое как EF Core, является современным объектно-базовым маппером для .NET. Он позволяет разработчикам работать с базой данных, используя .NET объекты, устраняя необходимость в большинстве кода, который разработчик обычно должен писать для доступа к данным.
EF Core является легким, extensible и cross-platform вариантом популярной технологии доступа к данным Entity Framework (EF). Он поддерживает различные движки баз данных, включая SQL Server, SQLite и MongoDB.
Одна из основных преимуществ использования EF Core заключается в том, что он позволяет разработчикам работать с данными более интуитивно и объектно-ориентированно. Вместо написания чистого SQL запроса, вы можете взаимодействовать с базой данных, используя LINQ ( Language Integrated Query) и strongly-typed классы.
Давайте посмотрим на простой пример. предположим, у нас есть класс Product
:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Это довольно простое, с только тремя полями.Utilizando EF Core, вы можете создать класс контекста, представляющий сеанс с базой данных, и включающий DbSet
для каждого типа сущностей, которые вы хотите выполнять запросы или сохранять:
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.Use<Your_SQL_Database_function>("YourConnectionStringHere");
}
}
Этот код определяет класс с именем AppDbContext
, который наследует от класса DbContext
Entity Framework Core. Этот класс используется для взаимодействия с базой данных. Внутри этого класса есть свойство DbSet<Product>
с именем Products
, которое представляет собой коллекцию сущностей Product
и соответствует таблице с именем Products
в базе данных. метод OnConfiguring
переопределяется для настройки подключения к базе данных; можно указать различные базы данных в качестве провайдера базы данных. Метод использует optionsBuilder
, чтобы установить соединение с заменителем для строки подключения к базе данных реальной. эта строка подключения явно должна быть заменена на истинную, содержащую необходимые детали для подключения к базе данных. когда вы создаете экземпляр AppDbContext
в приложении, он использует эту настройку для выполнения операций, таких как запрос или сохранение сущностей Product
в таблице Products
.
с помощью этой установки вы можете выполнять операции CRUD (Create, Read, Update, Delete) с использованием EF Core. например, чтобы добавить новый продукт в базу данных, вы можете использовать этот код.
using (var context = new AppDbContext())
{
var product = new Product { Name = "Laptop", Price = 999.99M };
context.Products.Add(product);
context.SaveChanges();
}
Этот код демонстрирует, как добавить новый продукт в базу данных с использованием Entity Framework Core. Быт создан экземпляр AppDbContext
, и внутри этого контекста создается новый объект Product
с именем “Laptop” и ценой 999.99. Этот новый продукт затем добавляется в коллекцию Products
, управляемую AppDbContext
. Finally, метод SaveChanges
вызывается для сохранения изменений в базе данных, что эффективно вставляет новый продукт в таблицу Products
.
Чтобы выполнять запросы на продукты, можно использовать 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}");
}
}
Этот код демонстрирует, как выполнять запросы к базе данных с использованием Entity Framework Core. Быт создан экземпляр AppDbContext
, и внутри этого контекста выполняется запрос для извлечения всех продуктов с ценой больше чем 500. Результаты сохраняются в списке, называемом products
. Затем цикл迭代遍历 каждого продукта в списке, выводя на консоль имя и цену каждого продукта.
EF Core позаботится о том, чтобы преобразовать эти запросы LINQ в соответствующие SQL- команды для вашей базы данных, что делает доступ к данным проще и более maintainable.
EF Core также поддерживает avanced функции, такие как трекирование изменений, поздняя загрузка и миграции, которые помогают вам управлять изменениями схемы базы данных с течением времени.
В общем, EF Core является мощным ORM, который упрощает доступ к данным в приложениях .NET, позволяя вам работать с данными, используя .NET объекты и LINQ. Его поддержка нескольких движков баз данных и его extendibility делают его гибким выбором для широкого круга приложений.
В следующем разделе мы увидим, как монгодб EF Core Provider соединяет различия между MongoDB и EF Core, позволяя нам использовать знакомыеpatterns EF Core с базой данных MongoDB.
Как монгодб EF Core Provider Бidges the Gap
MongoDB Entity Framework Core Provider – это инструмент, который позволяет разработчикам использовать MongoDB с Entity Framework Core (EF Core), сочетая гибкость MongoDB с знакомыми API и дизайн-паттернами EF Core. Этот провайдер позволяет вам работать с MongoDB используя те же методологии code-first и LINQ查询, которые вы использовали бы с реляционными базами данных, упрощая разработку и снижая learning curve для тех, кто уже знаком с EF Core.
MongoDB EF Core Provider bridge the gap between MongoDB and EF Core by supporting basic CRUD operations, LINQ queries, and embedded documents, among other features. Here are some key capabilities:
-
Code-First Workflows: You can define your data models in C# and use EF Core to generate the MongoDB schema, rather than starting with the database schema and generating code from it. This is particularly useful for developers who prefer to manage their database structure through code.
-
Операции CRUD: Провайдер поддерживает базовые операции создания, чтения, обновления и удаления. Например, вы можете добавить новую запись в базу данных используя то же самое код, который мы видели ранее:
using (var context = new AppDbContext()) { var product = new Product { Name = "Laptop", Price = 999.99M }; context.Products.Add(product); context.SaveChanges(); }
-
Поддержка запросов LINQ: Вы можете использовать LINQ для выполнения запросов к MongoDB, что позволяет использовать ваши существующие знания C# и .NET для взаимодействия с базой данных.
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}"); } }
-
Отслеживание изменений: Поддерживаются способности отслеживания изменений EF Core, что позволяет автоматически обнаруживать и сохранять изменения, внесенные в ваши сущности данных.
-
Встроенные документы: Провайдер поддерживает встроенные документы, что позволяет хранить связанные данные внутри одного документа, что является общим паттерном в MongoDB.
-
Картографирование классов и сериализация: Ваши классы C# сопоставляются с коллекциями MongoDB, с поддержкой различных типов данных и настроек сериализации для обеспечения правильного хранения данных.
Моделирование данных и операции CRUD с использованием MongoDB Atlas
Теперь мы пройдемся по быстрому примеру, как использовать провайдер MongoDB EF Core. Но вскоре мы создадим полный проект в Visual Studio Code, чтобы вы могли увидеть все в контексте.
В этом разделе мы изучим, как определять данные модели и выполнять операции CRUD (Create, Read, Update, Delete) с использованием MongoDB Entity Framework Core (EF) Provider с MongoDB Atlas. Эта интеграция позволяет вам использовать гибкость MongoDB с известными моделями EF Core.
Настройка вашего окружения
Для начала вам нужно добавить необходимые NuGet-пакеты в ваш проект:
dotnet add package MongoDB.EntityFrameworkCore
Пакет MS EF Core и MongoDB C# Driver добавляются в качестве зависимости, когда вы добавляете пакет провайдера MongoDB EF Core. Эти пакеты позволяют вашему приложению взаимодействовать с MongoDB через EF Core, используя те же контекст и определения сущностей, которые вы бы использовали с реляционной базой данных.
Настройка MongoDB Atlas
Перед тем, как вы можете выполнять операции CRUD, вам нужно настроить кластер MongoDB Atlas и связать ваше приложение с ним.
Вот шаги. Обратите внимание, что мы детально ознакомимся с ними, когда создадим проект.
-
Создание учетной записи MongoDB Atlas: Зарегистрируйтесь за free на MongoDB Atlas.
-
Создание кластера: Установите новый кластер. Сервис MongoDB Atlas предлагает бесплатный уровень, идеальный для разработки и маломасштабных приложений.
-
Получение строки соединения: Получите строку соединения с помощью панели управления MongoDB Atlas. Она выглядит примерно так:
mongodb+srv://<username>:<password>@cluster0.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
Определение данного модели
Определите класс, который будет использоваться в качестве модели для вашего объекта. В этом примере мы создадим класс Customer
:
public class Customer
{
public ObjectId Id { get; set; }
public String Name { get; set; }
public String Order { get; set; }
}
Этот класс Customer
представляет структуру документов, хранящихся в коллекции MongoDB.
Создание класса DB Context
Чтобы начать использовать Entity Framework Core, создайте класс контекста, который наследует от DBContext.インスタンция класса, наследующего от DbContext
, представляет сессию базы данных и используется для выполнения запросов и сохранения экземпляров ваших сущностей.
Класс DbContext
предоставляет свойства DBSet
, которые определяют сущности, с которыми можно взаимодействовать при использовании этого контекста.
Этот пример создает экземпляр класса, наследующего от DBContext
, и указывает объект Customer
в качестве свойства 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");
}
}
Работа с данными в режиме кода первого
С помощью провайдера MongoDB EF можно использовать работу с данными в режиме кода первого. Это意味着 вы определяете свои классы сначала, а EF Core будет обслуживать создание и управление подлежащим MongoDB схемой. Это особенно полезно для MongoDB, который не обеспечивает схему, позволяя гибкие и динамические структуры данных.
Использование MongoDB
После создания класса DBContext
нам нужно создать объект DbContextOptionsBuilder
и вызвать его метод UseMongoDB()
. Этот метод принимает два параметра: экземпляр MongoClient
и имя базы данных, в которой хранятся коллекции, с которыми вы работаете.
Метод UseMongoDB()
возвращает объект DbContextOptions
. Параметр Options
этого объекта нужно передать конструктору вашего класса DBContext
.
var mongoClient = new MongoClient("<Your MongoDB Connection URI>");
var dbContextOptions =
new DbContextOptionsBuilder<MyDbContext>().UseMongoDB(mongoClient, "<Database Name");
var db = new MyDbContext(dbContextOptions.Options);
Операции CRUD
Теперь посмотрим, как кодировать операции CRUD. Мы будем сосредотачиваться на каждой операции по отдельности.
Операция Create
Чтобы создать новый документ в MongoDB, вы используете метод Add
на DbSet
и вызываете метод SaveChanges
. Это пример создания нового клиента:
using (var context = new MyDbContext(options))
{
var customer = new Customer { Name = "Beau Carnes", Order = "Laptop" };
context.Customers.Add(customer);
context.SaveChanges();
}
Этот код создает новый экземпляр Customer
и добавляет его в коллекцию Customers
. Метод SaveChanges
сохраняет новые данные клиента в базу данных MongoDB.
Чтение операции
Для чтения документов из коллекции MongoDB вы можете использовать LINQ-запросы на DbSet
. Это пример извлечения всех клиентов:
using (var context = new MyDbContext(options))
{
var customers = context.Customers.ToList();
foreach (var customer in customers)
{
Console.WriteLine($"Customer: {customer.Name}, Order: {customer.Order}");
}
}
Этот код извлекает всех клиентов из коллекции Customers
и выводит их данные.
Операция обновления
Для обновления существующего документа вы извлекаете документ, изменяете его свойства и вызываете SaveChanges
. Это пример обновления заказа клиента:
using (var context = new MyDbContext(options))
{
var customer = context.Customers.FirstOrDefault(c => c.Name == "Beau Carnes");
if (customer != null)
{
customer.Order = "Smartphone";
context.SaveChanges();
}
}
Этот код находит клиента с именем “Beau Carnes” и обновляет его заказ на “Смартфон”.
Операция удаления
Для удаления документа вы извлекаете документ, удаляете его из DbSet
и вызываете SaveChanges
. Это пример удаления клиента:
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();
}
}
Этот код находит клиента с именем “Beau Carnes” и удаляет его из коллекции Customers
.
Отслеживание изменений
Возможности отслеживания изменений EF Core полностью поддерживаются, что обеспечивает эффективные обновления документов. При изменении энтити и вызове SaveChanges
, EF Core генерирует нужные MongoDB-команды для обновления только измененных полей.
Используя MongoDB EF Provider, вы можете гладко интегрировать гибкую модель документов MongoDB с мощными возможностями ORM EF Core, предоставляя мощный набор инструментов для .NET-разработчиков для создания современных приложений.
Tutorial
Теперь let’s put everything together and create a restaurant reservation system.
Prerequisites
Необходимо иметь следующее для прохождения данного урока:
-
.NET 7.0.
-
Базовые знания о ASP.NET MVC и C#.
-
Бесплатный аккаунт MongoDB Atlas и кластер бесплатного уровня.
Создание проекта
ASP.NET Core – это очень гибкая веб-фреймворк, позволяющая создавать различные типы веб-приложений, которые имеют небольшие различия в пользовательском интерфейсе или структуре. Для этого урока мы создадим проект MVC, который будет использовать статические файлы и контроллеры. Есть другие типы интерфейса, которые вы можете использовать, такие как React, но MVC с представлениями .cshtml наиболее широко используется. Чтобы создать проект, мы будем использовать .NET CLI:
dotnet new mvc -o RestRes
Поскольку мы использовали CLI, хотя это проще, он создает только файл csproj, а не файл решения, который позволяет нам открывать его в Visual Studio, поэтому мы исправим это.
cd RestRes
dotnet new sln
dotnet sln .\RestRes.sln add .\RestRes.csproj
Добавление NuGet-пакетов
Теперь, когда мы создали новый проект, мы продолжим и добавим требуемые пакеты NuGet. Используя либо менеджер пакетов NuGet, либо команду .NET CLI ниже, добавьте пакет MongoDB MongoDB.EntityFrameworkCore.
dotnet add package MongoDB.EntityFrameworkCore
Создание моделей
Перед тем, как мы можем начать реализовать новые пакеты, которые только что добавили, нам необходимо создать модели, которые представляют сущности, которые мы хотим в нашем системе резервации ресторанов, которая, конечно, будет храниться в MongoDB Atlas в качестве документов. В следующих подразделах мы создадим следующие модели:
-
Ресторан
-
Резервация
-
MongoDBSettings
Ресторан
Сначала нам нужно создать модель нашего ресторана, которая будет представлять рестораны, доступные для резервации в нашей системе.
-
Создайте новый файл в папке Models с именем Restaurant.cs.
-
Добавьте следующий код:
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; }
}
}
Attribute collection перед классом указывает приложению, какая коллекция в базе данных мы используем. Это позволяет нам иметь различные названия или Capitalization между нашей clas и нашей коллекцией, если мы хотим этого.
Резервация
我们还需要创建一个预订类来表示我们系统中的任何预订。
-
在 Models 文件夹内创建一个名为 Reservation.cs 的新文件。
-
向其中添加以下代码:
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
Несмотря на то, что это не будет документ в нашей базе данных, нам нужна модель класса для хранения настроек, связанных с MongoDB, чтобы их можно было использовать во всей приложении.
-
Создайте еще один файл в Models, называемый MongoDBSettings.cs.
-
Добавьте следующий код:
namespace RestRes.Models
{
public class MongoDBSettings
{
public string AtlasURI { get; set; }
public string DatabaseName { get; set; }
}
}
Настройка EF Core
Это замечательно. Мы собираемся начать реализовывать EF Core и воспользоваться новым провайдером MongoDB. Если вы уже работали с EF Core, часть этого вам известна.
RestaurantReservationDbContext
-
Создайте папку Services и создайте файл с именем RestaurantReservationDbContext.cs.
-
Замените код внутри namespaces следующим образом:
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>();
}
}
}
Если вы знакомы с EF Core, это вам понравится. Класс унаследован от DbContext, и мы создаем свойства DbSet, которые хранят модели, которые также будут присутствовать в базе данных. Мы также переопределяем метод OnModelCreating. Вы, скорее всего, заметите, что в отличие от использования SQL Server мы не вызываем .ToTable(). Мы могли бы вызвать ToCollection, но это здесь не требуется, так как мы указываем коллекцию с помощью атрибутов в классах.
Добавьте строку соединения и данные базы данных в appsettings.
Раньше мы создали модель MongoDBSettings, и теперь нам нужно добавить значения, к которым свойства относятся, в наш appsettings.
-
В both appsettings.json и appsettings.Development.json добавьте следующий новый раздел:
"MongoDBSettings": { "AtlasURI": "mongodb+srv://<username>:<password>@<url>", "DatabaseName": "restaurants" }
-
Замените URI Atlas на ваш собственный строку подключения с Atlas.
Обновление program.cs
Теперь, когда мы настроили наши модели и DbContext, пришло время добавить их в наш файл program.cs.
После существующей строки builder.Services
.AddControllersWithViews();
, добавьте следующий код:
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 ?? ""));
Создание услуг
Теперь пора добавить сервисы, которые будут использоваться для работы с базой данных через RestaurantBookingDbContext, который мы создали. Для каждого сервиса мы создадим интерфейс и класс, реализующий этот интерфейс.
IRestaurantService и RestaurantService
Первым интерфейсом и сервисом, который мы будем реализовать, будет для выполнения CRUD операций с коллекцией ресторанов. Это известно как паттерн репозитория. Можете видеть, как люди работают с DbContext напрямую. Но большинство людей использует этот паттерн, поэтому мы его включим в это место.
-
Если вы еще не сделали это, создайте папку Services, чтобы хранить наши новые классы.
-
Создайте интерфейс IRestaurantService и добавьте следующий код для методов, которые мы будем реализовать:
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);
}
}
-
Создайте файл класса RestaurantService.
-
Обновите декларацию класса RestaurantService, чтобы он реализовал интерфейс IRestaurantService, который мы только что создали:
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 и ReservationService
Next up is our IReservationService and ReservationService.
Create the IReservationService interface and add the following methods:
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);
}
}
Создайте класс ReservationService и замените ваш класс следующим кодом, который реализует все методы:
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);
}
}
}
Этот код очень схож с кодом для класса RestaurantService, но он предназначен для бронирования.
Добавление в зависимость от внешних ресурсов
Последний шаг для служб – это добавление их в контейнер зависимостей.
Внутри файла Program.cs, добавьте следующий код после предыдущего, добавленного ранее:
builder.Services.AddScoped<IRestaurantService, RestaurantService>();
builder.Services.AddScoped<IReservationService, ReservationService>();
Создание view models
Перед реализацией front end-а нам нужно добавить view models, которые будут выполнять роль посредника между front end-ом и back end-ом, где требуется. Если though наша приложение довольно простое, реализация view model仍然是 хорошая практика, поскольку она помогает разделить различные части приложения.
RestaurantListViewModel
Первым, которое мы добавим, будет RestaurantListViewModel. Это будет использоваться как модель в нашем Razor page позднее для отображения ресторанов в нашей базе данных.
-
Создайте новую папку в корне проекта под названием ViewModels.
-
Добавьте новый файл под названием RestaurantListViewModel.cs.
-
Добавьте следующий код:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantListViewModel
{
public IEnumerable<Restaurant>? Restaurants { get; set; }
}
}
RestaurantAddViewModel
Мы также хотим view model, который может использоваться в Add view, который мы добавим позднее.
-
Внутри папки ViewModels создайте новый файл под названием RestaurantAddViewMode.cs.
-
Добавление:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantAddViewModel
{
public Restaurant? Restaurant { get; set; }
}
}
ReservationListViewModel
Теперь мы хотим сделать что-то очень похожее для броней, начиная с ReservationListViewModel.
-
Создайте новый файл в папке ViewModels с именем ReservationListViewModel.cs.
-
Добавление:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationListViewModel
{
public IEnumerable<Reservation>? Reservations { get; set; }
}
}
ReservationAddViewModel
В конце концов, у нас есть ReservationAddViewModel.
Создайте файл и добавьте этот код:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class ReservationAddViewModel
{
public Reservation? Reservation { get; set; }
}
}
Добавление в _ViewImports
Позднее мы будем добавлять ссылки на наши модели и viewmodelы в представления. Чтобы приложение знало, о чем идет речь, мы должны добавить ссылки на них в файл _ViewImports.cshtml в папке Views.
В нём уже будут какие-то ссылки, включая TagHelpers, поэтому мы хотим добавить ссылки на наши папки .Models и .ViewModels. Так что верхняя часть файла должна выглядеть так:
@using RestRes
@using RestRes.Models
@using RestRes.ViewModels
Создание контроллеров
Теперь, когда у нас есть backend реализация и viewmodelы, которые мы будем использовать, мы можем начать работать в сторону front end. Мы создадим два контроллера: один для ресторана и один для броней.
RestaurantController
Первым контроллером, который мы добавим, будет для ресторана.
-
Внутри существующей папки Controllers добавьте новый файл контроллера с именем RestaurantController.cs. Если вы используете Visual Studio, воспользуйтесь шаблоном MVC Controller – Empty (пустой контроллер).
-
Добавьте следующий код:
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
Теперь для контроллера бронирования. Это очень похоже на RestaurantController, но у него есть ссылка на сервис ресторана и бронирования, так как нам нужно связать ресторан с бронированием. Это связано с тем, что в настоящее время провайдер EF Core не поддерживает отношения между сущностями, поэтому мы можем связывать сущности другим способом.
-
Создайте другой пустой файл контроллера MVC с именем ReservationController.cs.
-
Вставьте следующий код:
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);
}
}
}
Создание представлений
Теперь, когда у нас есть бэкенд и контроллеры, настроенные с конечными точками для системы бронирования ресторанов, пришло время implementировать представления. Мы будем использовать страницы Razor. Также вы увидите ссылки на классы из Bootstrap, поскольку это CSS-фреймворк, который идет в комплекте с приложениями MVC. Мы предоставим представления для операций CRUD для списков и бронирований.
Список ресторанов
Сначала мы предоставим представление, которое будет соответствовать корневому узлу /Restaurant, который по конвенции будет искать метод Index, который мы реализовали.
ASP.NET Core MVC использует Paradigma соглашений, где вы называете .cshtml файл именем endpoint/метода и он располагается в папке с именем контроллера.
-
Внутри папки Views, создайте новую подпапку с именем Restaurant.
-
Внутри этой папки Restaurant, добавьте новую вьюзу, создав файл с именем
Index.cshtml
. Если использовать доступные шаблоны, вы хотите Razor View – Empty. Назовите вьюзу Index. -
Добавьте следующий код:
@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>
Теперь let’s обновить default роут от Home до /Restaurant.
В Program.cs, внутри app.MapControllerRoute
, замените линию с шаблоном следующим образом:
pattern: "{controller=Restaurant}/{action=Index}/{id?}");
Если мы запустим это сейчас, кнопки приведут к 404, поскольку мы еще их не реализовали. Так что начнем с этого сейчас.
Добавление ресторанов
Начнем с формы для добавления новых ресторанов.
-
Добавьте новую, пустую Razor View в подпапке Restaurant с именем Add.cshtml.
-
Добавьте следующий код:
@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>
Редактирование ресторанов
Код для страницы редактирования практически идентичен странице добавления, но он использует Ресторан как модель, поскольку он будет использовать ресторан, который ему передается, чтобы предварительно заполнить форму для редактирования.
-
Добавьте еще одну вью в подпапке Рестораны, называемую Edit.cshtml.
-
Добавьте следующий код:
@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>
Удаление ресторанов
Последняя страница, которую нам надо реализовать, это страница, которая вызывается при нажатии кнопки удаления.
-
Создайте новую пустую вью called Delete.cshtml.
-
Добавьте следующий код:
@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>
Список броней
Мы добавили вью для ресторанов, теперь мы добавим вью для броней, начиная с создания списка существующих броней.
-
Создайте новую папку внутри папки Views, называемую Reservation.
-
Создайте новый пустой файл вьюшки called Index.cshtml.
-
Добавьте следующий код для отображения броней, если они существуют:
@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>
}
Добавление броней
Добавление броней происходит после.
-
Создайте пустую вьюху с именем Add.cshtml.
-
Добавьте следующий код:
@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>
Редактирование броней
Следующим шагом является редактирование броней.
-
Создайте пустую вьюху с именем Edit.cshtml.
-
Добавьте следующий код:
@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>
Удаление броней
Следующим шагом является удаление броней.
-
Создайте пустую вьюху с именем Delete.cshtml.
-
Добавьте следующий код:
@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>
Обновление NavBar
Последним действием является обновление меню навигации приложения, чтобы мы могли легко переключаться между ресторанами и бронями.
Перейдите к файлу Views/Shared/_Layout.cshtml
. Найдите div
с классом navbar-collapse
. Удалите всю эту секцию и добавьте следующий код:
<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>
Тестирование нашего приложения
Теперь у нас есть работающая приложения, использующая новый MongoDB Provider для EF Core. Пришло время протестировать его и посетить наши endpoint’ы, чтобы убедиться, что все работает.
В терминале запустите следующий запрос:
dotnet run
Попробуйте редактировать рестораны и добавлять бронирования. Затем перейдите на страницу базы данных MongoDB Atlas и увидите, что изменения отражены в базе данных.
Продвижение MongoDB: поиск Atlas и векторный поиск
Провайдер EF Core основан на драйвере MongoDB C#. Так как у нас уже есть доступ к MongoClient при создании DbContext, это позволяет нам выполнять продвижущие операции MongoDB, такие как поиск Atlas и векторный поиск. Эти функции улучшают возможности вашего приложения, позволяя реализовать мощные поисковые функции и использовать знакомый фреймворк EF Core.
Поиск Atlas
Поиск Atlas — это полнотекстовый поисковик, предоставляемый MongoDB Atlas. Он позволяет выполнять сложные запросы на данных MongoDB. С помощью поиска Atlas можно реализовать такие функции, как автоподстановка, разделённый поиск и сортировка по значимости.
Чтобы использовать поиск Atlas с помощью провайдера EF Core, выполните следующие шаги:
-
Настройка индексов в MongoDB Atlas:
-
Перейдите к кластеру MongoDB Atlas.
-
Перейдите к вкладке “Поиск” и создайте новый индекс в вашей коллекции.Define the fields you want to make searchable.
-
-
Определение поисковых полей в ваших моделях: Убедитесь, что поля, в которых вы хотите выполнять поиск, были правильно определены в ваших C# моделях. Вот пример определения модели Product.
<код class="language-csharp"> <ключевое слово>public < класс>class < класс>Product < закрывающая скобка>{ <ключевое слово>public <тип возврата>ObjectId Id < закрывающая скобка>{
get ;set < закрывающая скобка>} <ключевое слово>public <тип возврата>Name < закрывающая скобка>{ get ;set < закрывающая скобка>} <ключевое слово>public <тип возврата>Description < закрывающая скобка>{ get ;set < закрывающая скобка>} <ключевое слово>public <тип возврата>Price < закрывающая скобка>{ get ;set < закрывающая скобка>} <ключевое слово>public <тип возврата>Category < закрывающая скобка>{ get ;set < закрывающая скобка>} < закрывающая скобка>} -
Выполнение поисковых запросов: Используйте возможности драйвера MongoDB .NET для выполнения текстовых поисков. Поскольку EF Core самостоятельно не поддерживает специфическую для MongoDB синтаксис поиска, вам потребуется использовать драйвер в сочетании с EF Core. Вот пример:
using MongoDB.Driver; using MongoDB.Driver.Linq; var client = new MongoClient("ваша-строка-подключения-к-mongodb"); var database = client.GetDatabase("название-вашей-базы-данных"); var collection = database.GetCollection<Product>("Products"); var searchResult = collection.Aggregate() .Match(Builders<Product>.Filter.Text("термин-поиска")) .ToList();
В этом примере показано, как выполняется текстовый поиск в коллекции Products
. Фильтр Text
помогает искать в всех заданных в индексе Atlas Search полях.
Векторный поиск
Векторный поиск в MongoDB используется для поиска документов на основе сходства векторов, что особенно полезно в приложениях, включающих машинное обучение, рекомендации и природное языковедение. Векторный поиск позволяет запрашивать документы с использованием векторов, представляющих текст, изображения или другие высокоразмерные данные.
-
Создание и хранение векторов: Сначала убедитесь, что ваши документы содержат векторы. Вы можете необходимо пред обработать свои данные, чтобы генерировать这些 вектора с использованием моделей машинного обучения.
-
Индексирование векторов в MongoDB Atlas: Создайте специальный индекс на векторном поле в MongoDB Atlas, чтобы облегчить эффективные поиски сходства векторов.
- Выполнение векторных поисков: Используйте драйвер MongoDB .NET для запросов на основе схожести векторов.
Интеграция с EF Core
Хотя провайдер MongoDB EF Core упрощает операции CRUD, некоторые продвинутые функции, такие как поиск Atlas и векторный поиск, требуют прямого использования драйвера MongoDB .NET. Тем не менее, вы можете все еще интегрировать эти операции в ваше приложение на базе EF Core, используя драйвер для функций поиска и EF Core для других задач управления данными.
Сочетая EF Core и продвинутые функции MongoDB, вы можете создавать мощные и гибкие приложения, используя лучшее из обоих миров – структурированные паттерны доступа данных EF Core и мощные возможности поиска MongoDB Atlas.
Source:
https://www.freecodecamp.org/news/using-entity-framework-core-with-mongodb/