实体框架核心是一個流行的 ORM(物件關係映射器)對於 .NET 應用程式,讓開發者可以使用 .NET 物件與資料庫進行互動。它可以用於多種類型的資料庫,包括 MongoDB。
在本文中,您將學習如何使用 MongoDB 配合 Entity Framework Core。本文涵盖了基礎知識,解釋了優點,並提供了步驟化的教程。無論您是剛開始接触 MongoDB 或 Entity Framework Core,或者只是想在您的 .NET 项目中整合這些工具,本指南將幫助您橋接關係型和 NoSQL 資料庫之間的差異。
文章從對 MongoDB 的簡短介紹以及 Microsoft 的 Entity Framework Core 的介紹開始。然後,它覆盖了如何使用 MongoDB EF Core 提供者。在通過一些基本示例進行技術詳細介绍後,您將使用 MongoB 和 Entity Framework Core 創建一個完整項目,以便您可以了解所有內容是如何一起工作的。該項目將使用 MongoDB Atlas 示例數據來創建一個餐廳預約系統。
本文還有一個視頻版本,您可以在 freeCodeCamp.org YouTube 頻道上 收看了解。
MongoDB 簡介
MongoDB 是一個流行的 NoSQL 資料庫,設計用來處理大量的數據,并提供高性能、可擴展性和靈活性。與傳統的關係型數據庫不同,MongoDB 以靈活的 JSON 類似的文檔來存儲數據。這種 文档导向的方法允許以更自然和直觀的方式存儲複雜的數據結構。
在 MongoDB 中,數據是存儲在 Collections 中的,這些 Collections 類似於關係型數據庫中的表,但沒有固定的結構。這意味著你可以在同一個 Collection 中擁有結構不同的文檔。這種靈活性是使用 MongoDB 的關鍵优势之一,特別是當處理非結構化或半結構化數據時。
讓我們来看一個 MongoDB 文檔的例子。假設我們有一個叫作 users
的 Collection,用來存放一個應用程序中用戶的信息。以下是一個典型的文檔可能會看起來像什麼:
{
"_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 還支持 richer 查詢、索引和聚合,使其成為各種應用程序的强大工具。
例如,你可以執行一個查詢以找出所有住在特定城市的用戶:
db.users.find({ "address.city": "Anytown" })
你可以尋找對特定愛好有興趣的用戶:
db.users.find({ "hobbies": "coding" })
MongoDB在各種行業中都有廣泛的應用,從電子商務和內容管理到即時分析與物聯網(IoT)應用。其靈活性与可擴展性使其成為需要處理多樣且动态数据的現代應用程序的杰出選擇。
現在我們已經有了對MongoDB是什麼以及為什麼它受欢迎的基本了解,讓我們繼續學習我們技術栈中的另一個重要工具:Microsoft的Entity Framework Core。
Microsoft Entity Framework Core简介
Entity Framework Core,通常簡稱為EF Core,是.NET的現代面向对象的數據庫映射工具。它讓開發者可以使用.NET對象與數據庫工作,從而消除開發者通常需要撰寫的大部分數據访问代碼。
EF Core是流行的Entity Framework(EF)數據访问技術的轻量级、可擴展和跨平台版本。它支持多種數據庫引擎,包括SQL Server、SQLite和MongoDB。
使用EF Core的主要好處之一是它讓開發者可以以更直觀和面向对象的方式的處理數據。你不需要寫原始SQL查詢,而是可以使用LINQ(語言整合查詢)和強型別類型與你的數據庫進行交雲。
讓我們来看一個基本的示例。假設我們有一個Product
類:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
這個相對簡單,只有三個字段。使用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
的類別,該類別繼承自Entity Framework Core的DbContext
類別。這個類別用於與數據庫進行互動。在這個類別內,有一個名為Products
的DbSet<Product>
屬性,它代表一個Product
實體的集合,對應於數據庫中的一個名為Products
的表。OnConfiguring
方法被覆寫用以配置數據庫連接,您可以指定各種數據庫作為數據庫提供者。該方法使用optionsBuilder
來設定與实际數據庫連接字符串的連接。這個連接字符串顯然應該被替換為包含正確 detailed connection information 的真正字符串。當您在應用程序中創建AppDbContext
實例時,它會使用此配置來執行如查詢或保存Product
實體到Products
表等操作。
透過這種設定,您可以使用EF Core執行CRUD(建立、讀取、更新、刪除)操作。例如,要將新产品添加到數據庫,您可以使用此代碼。
using (var context = new AppDbContext())
{
var product = new Product { Name = "Laptop", Price = 999.99M };
context.Products.Add(product);
context.SaveChanges();
}
以下程式碼展示了如何使用 Entity Framework Core將新品增加到數據庫中。首先建立 AppDbContext
的實例,在此上下文中,建立了一個新产品 Laptop
物件,並設定其名稱為「筆記型電腦」及價格為 999.99。這個新产品然後被加入到由 AppDbContext
管理之 Products
集合中。最後呼叫 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 命令,使數據访问變得更加簡單且易於維護。
EF Core 也支持進階功能,例如變更追蹤、延遲加載和迁移,這些功能能幫助您隨著時間推移管理數據庫架構的變更。
總結來說,EF Core 是一個強大的 ORM 工具,它通過允許您使用 .NET 物件和 LINQ 來操作數據,簡化了 .NET 應用程序中的數據訪問。它對多種數據庫引擎的支持以及其擴展性使其成為各種應用程序的Universal選擇。
接下來的內容將介绍MongoDB EF Core Provider如何橋接MongoDB和EF Core之間的差異,讓我們能夠使用熟悉的EF Core模式來操作MongoDB資料庫。
MongoDB EF Core Provider如何橋接差異
MongoDB Entity Framework Core Provider是一個工具,讓開發者能夠使用MongoDB與Entity Framework Core (EF Core),結合MongoDB的靈活性与EF Core熟悉的API和設計模式。這個提供者讓您可以使用與關係型數據庫相同的code-first和LINQ查詢方法,簡化開發流程並減少對熟悉EF Core的开发者來說的學習曲線。
MongoDB EF Core Provider通過支持基本的CRUD操作、LINQ查詢和嵌入式文件等功能,橋接MongoDB和EF Core之間的差異。以下是一些关键技术能力:
-
Code-First工作流程:您可以定義在C#中的數據模型,並使用EF Core生成MongoDB架构,而不是從數據庫架构開始並從中生成代碼。這對於偏好通過代碼管理數據庫結構的開發者來說尤其有用。
-
CRUD 操作:供應商支持基本的創建、讀取、更新和刪除操作。例如,您可以使用我們之前看過的同一份代碼,將新的記錄添加到數據庫中:
using (var context = new AppDbContext()) { var product = new Product { Name = "筆記型電腦", 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 集合,並支持各種數據型態和序列化設定,以确保數據正確存儲。
使用 MongoDB Atlas 進行數據建模和 CRUD 操作
現在我們將 quickly go over an example of how to use the MongoDB EF Core Provider. But soon, we’ll create a full project in Visual Studio Code so you can see everything in context.
在本部分中,我們將探討如何使用 MongoDB Entity Framework Core(EF)提供者與 MongoDB Atlas 定義數據模型並執行 CRUD(Create、Read、Update、Delete)操作。此集成使您可以將 MongoDB 的靈活性與 EF Core 的熟悉模式結合起來。
設置您的環境
要開始,您需要將必要的 NuGet 套件添加到您的項目中:
dotnet add package MongoDB.EntityFrameworkCore
當您添加 MongoDB EF Core 提供者套件時,將 MS EF Core 套件和 MongoDB C# Driver 添加為依賴項。這些套件使您的應用程序可以通過 EF Core 與 MongoDB 進行交互,使用與關聯式數據庫相同的上下文和實體定義。
設置 MongoDB Atlas
在執行 CRUD 操作之前,您需要設置一個 MongoDB Atlas 集群並將應用程序連接到該集群。
以下是步驟。請注意,我們將在不久之後創建項目時詳細介紹這些步驟。
-
創建 MongoDB Atlas 帳戶:在 MongoDB Atlas 上註冊免費帳戶。
-
建立簇集:設定一个新的簇集。MongoDB Atlas 提供免费的層次,非常適合開發和小型應用。
-
獲取連接字符串:從 MongoDB Atlas 控制面板獲取您的連接字符串。它看起來可能會像這樣:
mongodb+srv://
: @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 情境類
為了開始使用 Entity Framework Core,創建一個從 DBContext 派生的情境類。DbContext
派生類實例代表一個數據庫會話,並用於查询和保存您的实体副本。
DbContext
類暴露 DBSet
屬性,指定了在使用該情境時您可以Interact 的实体。
這個例子創建了一個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");
}
}
Code-First 工作流程
使用 MongoDB EF 提供程序,您可以使用 code-first 工作流程。這意味著您先定義您的類,然後 EF Core 將處理底層 MongoDB 架構的創建和管理。這對於 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 操作。我們將集中研究每個操作獨立進行。
創建操作
要在 MongoDB 中創建新的文檔,您使用DbSet
上的Add
方法並調用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集合中讀取文件,您可以使用DbSet
上的LINQ查詢。这是一个检索所有客户的例子:
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提供程序,您可以无缝地將MongoDB靈活的文件模型與EF Core強大的ORM功能集成,為.NET開發者提供一個建造現代應用程序的强大工具集。
教程
現在讓我們將所有內容放在一起,創建一個餐廳預約系統。
前提條件
為了跟從本教學,你將需要以下幾樣东西:
-
.NET 7.0.
-
ASP.NET MVC 和 C# 的基本知識。
創建專案
ASP.NET Core 是一個非常靈活的 Web 框架,讓你能夠建制出在 UI 或結構上略有差異的不同類型的 Web 應用程式。對於本教學,我們将要創建一個將使用靜態文件和控制器的 MVC 項目。你也可以使用如 React 之類的其他前端,但 .cshtml 視圖的 MVC 是最常被使用的。為了創建項目,我們將使用 .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
建立模型
在我們可以開始實作剛剛新增的套件之前,我們需要創建代表我們希望在餐廳訂位系統中存放的 entities 的模型,這些模型將會存放在 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; }
}
}
类前面的集合屬性告訴應用程序我們在數據庫中使用哪个集合。這讓我們可以有不同的命名或大小寫之間我們的类和我們的集合,如果我們想的話。
訂位
我們還需要創建一個訂位類來代表我們系統中的任何訂位。
-
在 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 的文件。
-
將命名空間內的全體代碼替換為以下內容:
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 而不是 ToTable(),但在此处這是沒有必要的,因為我們通過類屬性指定集合。
將連接字符串和數據庫詳細信息添加到 appsettings
先前,我們創建了一個 MongoDBSettings 模型,現在我們需要將屬性映射到的值加入到我們的 appsettings.
-
在 appsettings.json 和 appsettings.Development.json 中,新增以下新的部分:
"MongoDBSettings": { "AtlasURI": "mongodb+srv://<username>:<password>@<url>", "DatabaseName": "restaurants" }
-
將 Atals URI 更改為從 Atals 取得的自身连线字符串。
更新 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
我們首先要實現的第一個接口和服務是用於對restaurants集合進行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
接下來的我們的IReservationService和ReservationService。
创建IReservationService接口并添加以下方法:
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>();
創建視圖模型的
在實現前端之前,我們需要添加作為我們前端和後端之間的通讯員的視圖模型。即使我們的應用程序很简单,實現視圖模型仍然是好的實踐,因為它有助於解耦應用程序的各個部分。
RestaurantListViewModel
我們首先要添加的是 RestaurantListViewModel。這將作為我們後續在 Razor 頁面上列印数据库中餐廳的模型。
-
在項目的根目錄中創建一個名為 ViewModels 的新文件夾。
-
添加一個稱為 RestaurantListViewModel.cs 的新文件。
-
添加以下代碼:
using RestRes.Models;
namespace RestRes.ViewModels
{
public class RestaurantListViewModel
{
public IEnumerable<Restaurant>? Restaurants { get; set; }
}
}
RestaurantAddViewModel
我們也想有一個可以用於後續新增視圖的視圖模型。
-
在 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; }
}
}
Adding to _ViewImports
稍後,我們將在查看器中添加對我們的模型和视图模型的引用。為了讓應用程序知道它們是什麼,我們需要在查看器文件夾内的 _ViewImports.cshtml 文件中添加對它們的引用。
那裡已經有一些引用,包括 TagHelpers,因此我們要添加對我們的 .Models 和 .ViewModels 文件夾的引用。因此,文件的頂部應該看起来像這樣:
@using RestRes
@using RestRes.Models
@using RestRes.ViewModels
Creating the controllers
現在我們已經有了後端實現和我們將引用的視圖模型,我們可以開始著手於前端。我們將建立兩個控制器:一個用於餐廳,一個用於預約。
RestaurantController
我們將添加的第一個控制器是用於餐廳的。
-
在现有的Controllers文件夾內,新增一個叫做RestaurantController.cs的控制器文件。如果使用Visual Studio,請使用MVC控制器 – 空控制器模板。
-
新增以下代碼:
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非常類似,但它同時 References 了餐廳和訂位服務,因為我們需要將餐廳與訂位關聯。這是因為目前,EF Core Provider 不支援 entities 之間的關係,因此我們可以以不同的方式相關 entities。
-
創建另一個空的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);
}
}
}
創建視圖
現在我們已經為餐廳訂位系統準備了後端和控制器,並為其设定了端點,是时候實作視圖了。這將使用Razor页面。你也會看到對Bootstrap類的引用,因為這是一個與MVC應用程序一同提供的CSS框架。我們將提供對於列表和預約的CRUD操作的視圖。
餐廳列表
首先,我們將提供一個視圖,它將映射到`/Restaurant`的根目錄,根據惯例,它將查看我們實現的`Index`方法。
ASP.NET Core MVC使用一種惯例模式,您將.cshtml文件的名稱命名為其端點/方法的名稱,並且它存儲在以其控制器命名的一个文件夾中。
-
在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>
現在讓我們將默認路徑從Home更改为/Restaurant。
在Program.cs中,在app.MapControllerRoute
內,將模式行替換為以下內容:
pattern: "{controller=Restaurant}/{action=Index}/{id?}");
如果我们現在運行這個,按鈕將會導向404,因為我們還沒有實現它們。所以讓我們現在就做吧。
添加餐廳
我們將從添加新餐廳的表單開始。
-
在Restaurant子文件夾內添加一個新的空Razor View,稱為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>
編輯餐廳
編輯頁面的代碼几乎與添加相同,但它使用餐廳作為模型的基础上,因為它將使用傳遞給它的餐廳預填充表單以進行編輯。
-
在Restaurant子文件夾內添加另一個叫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>
刪除餐廳
我們需要實現的最後一頁是當按鈕被點擊時調用的一頁。
-
建立一個新的空視圖叫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。
-
建立一個新的空視圖文件叫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>
}
添加訂位
增加預約 Next, add reservations.
-
建立一個空白的查看叫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>
编辑預約 Editing reservations
下一步是编辑預約。
-
建立一個空白的查看叫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>
刪除預約 Deleting reservations
下一步是刪除預約。
-
建立一個空白的查看叫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
文件。找到class为navbar-collapse
的div
。移除該整個部分,並加入以下代碼:
<div class="collapse navbar-collapse justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Restaurant" asp-action="Index">Restaurants</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Reservation" asp-action="Index">Reservations</a>
</li>
</ul>
</div>
测试我们的应用 Testing our application
現在我們有一個使用新的MongoDB Provider for EF Core功能的應用程序。现在是测试它并访问我们的端点以确保一切正常的时候了。
在终端中运行以下命令:
dotnet run
尝试編輯餐廳並添加訂位。然後您可以導航到MongoDB Atlas數據庫頁面,並看到您的更改在數據庫中反映出來。
進階MongoDB操作:Atlas搜索和向量搜索
EF Core提供商是建立在MongoDB C# Driver之上的。因為在創建DbContext時我們已經有权限使用MongoClient,這使我們能夠進行如Atlas搜索和向量搜索等進階MongoDB操作。這些功能通過启用強大的搜索功能並 still利用熟悉的EF Core框架,增強了您的應用程序的 capabilities。
Atlas搜索
Atlas搜索是由MongoDB Atlas提供的全文搜索引擎。它允許您在MongoDB數據上運行複雜的搜索查詢。借助Atlas搜索,您可以實現如自动完成、的面板搜索和相關性排序等特性。
要使用與EF Core提供商一起的Atlas搜索,請按照以下步驟操作:
-
在MongoDB Atlas中設定索引:
-
前往您的MongoDB Atlas集群。
-
轉向”搜索”标签並為您的收藏创建新的索引。定義您想要使其可搜索的字段。
-
-
在您的模型中定義可搜索字段:在您的 C# 模型中,請確保正確定義您想要搜索的字段。以下是 Product 模型的定義示例。
public class Product { public ObjectId Id { get; set; } public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } public string Category { get; set; } }
-
執行搜尋查詢:使用 MongoDB .NET 驅動程式的功能來進行文字搜尋。由於 EF Core 本身不直接支援 MongoDB 專有的搜尋語法,因此您需要將驅動程式與 EF Core 一起使用。以下是一個範例:
using MongoDB.Driver; using MongoDB.Driver.Linq; var client = new MongoClient("your-mongodb-connection-string"); var database = client.GetDatabase("your-database-name"); var collection = database.GetCollection<Product>("Products"); var searchResult = collection.Aggregate() .Match(Builders<Product>.Filter.Text("search term")) .ToList();
此示例展示了如何在 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 的進階功能,您可以建造強大且靈活的應用程序, leveraged the best of both worlds —— the structured data access patterns of EF Core and the powerful search capabilities of MongoDB Atlas.
Source:
https://www.freecodecamp.org/news/using-entity-framework-core-with-mongodb/