实体框架核心(Entity Framework Core)是.NET应用程序中流行的ORM(对象关系映射器),它允许开发人员使用.NET对象与数据库交互。它支持多种类型的数据库,包括MongoDB。
在这篇文章中,您将学习如何使用Entity Framework Core与MongoDB配合使用。本文涵盖了基础知识,解释了优势,并提供了分步教程。无论您是MongoDB或Entity Framework Core的新手,还是只是希望将这些工具集成到您的.NET项目中,本指南都将帮助您弥合关系型数据库和非关系型数据库之间的鸿沟。
文章从对MongoDB的简短介绍以及微软的实体框架核心开始。然后,它介绍了如何使用MongoDB EF Core提供程序。在通过一些基本示例介绍技术细节之后,您将使用MongoDB和实体框架核心创建一个完整的项目,以便您可以了解所有内容如何协同工作。该项目将使用MongoDB Atlas示例数据创建一个餐厅预订系统。
本文还有一个视频版本,您可以在freeCodeCamp.org YouTube频道上观看。
MongoDB简介
MongoDB是一种流行的NoSQL数据库,旨在处理大量数据并提供高性能、可扩展性和灵活性。与传统的关系型数据库不同,MongoDB以灵活的、类似JSON的文档形式存储数据。这种面向文档的方法允许以更自然、更直观的方式存储复杂数据结构。
在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 在各个行业中广泛使用,从电子商务和内容管理到实时分析和物联网(IoT)应用。其灵活性和可扩展性使其成为处理多样化和动态数据的现代应用程序的理想选择。
现在我们已经对 MongoDB 是什么以及为什么它受欢迎有了基本的了解,接下来让我们继续介绍我们技术栈中的另一个重要工具:微软的实体框架核心(Entity Framework Core)。
介绍微软的实体框架核心
实体框架核心,通常缩写为 EF Core,是 .NET 的现代对象-数据库映射工具。它允许开发人员使用 .NET 对象与数据库交互,消除了编写大多数数据访问代码的需要。
EF Core 是流行的实体框架(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
` 使用此设置,您可以使用 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应用程序中的数据访问。它对多种数据库引擎的支持和可扩展性使其成为各种应用程序的灵活选择。
接下来,我们将看到 MongoDB EF Core 提供程序如何弥合 MongoDB 和 EF Core 之间的差距,使我们能够使用熟悉的 EF Core 模式与 MongoDB 数据库一起工作。
MongoDB EF Core 提供程序如何弥合差距
MongoDB 实体框架核心提供程序是一种工具,使开发人员能够将 MongoDB 与实体框架核心(EF Core)一起使用,将 MongoDB 的灵活性与 EF Core 的熟悉的 API 和设计模式结合起来。此提供程序允许您使用与关系数据库相同的代码优先和 LINQ 查询方法来处理 MongoDB,简化开发并降低对已经熟悉 EF Core 的人员的学习曲线。
MongoDB EF Core 提供程序通过支持基本的 CRUD 操作、LINQ 查询和嵌入文档等功能,弥合了 MongoDB 和 EF Core 之间的差距。以下是一些关键功能:
-
代码优先工作流程:您可以在 C# 中定义数据模型,并使用 EF Core 生成 MongoDB 架构,而不是从数据库架构开始并从中生成代码。这对于那些更喜欢通过代码管理数据库结构的开发人员特别有用。
-
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集合,支持各种数据类型和序列化设置,以确保数据正确存储。
使用MongoDB Atlas进行数据建模和CRUD操作
现在,我们将通过一个快速示例来介绍如何使用MongoDB EF Core提供商。但很快,我们将在Visual Studio Code中创建一个完整的项目,以便您可以在上下文中查看所有内容。
在本节中,我们将探讨如何使用MongoDB Entity Framework Core (EF) 提供程序与MongoDB Atlas定义数据模型并执行CRUD(创建、读取、更新、删除)操作。此集成允许您利用MongoDB的灵活性与EF Core的熟悉模式。
设置您的环境
首先,您需要将必要的NuGet包添加到您的项目中:
dotnet add package MongoDB.EntityFrameworkCore
当您添加MongoDB EF Core提供程序包时,MS EF Core包和MongoDB C#驱动程序会被添加为依赖项。这些包允许您的应用程序通过EF Core与MongoDB交互,使用与关系数据库相同的上下文和实体定义。
设置MongoDB Atlas
在您执行CRUD操作之前,您需要设置一个MongoDB Atlas集群并将您的应用程序连接到它。
以下是步骤。请注意,我们将在创建项目时详细介绍这些步骤。
-
创建MongoDB Atlas账户:在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上下文类
为了开始使用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不强制执行架构,允许灵活和动态的数据结构。
使用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
创建模型
在开始实施我们刚刚添加的新包之前,我们需要创建表示我们希望在餐厅预订系统中存在的实体的模型,这些模型当然将存储在MongoDB Atlas中作为文档。在以下小节中,我们将创建以下模型:
-
餐厅
-
预订
-
MongoDB设置
餐厅
首先,我们需要创建一个餐厅模型,以表示系统中可预订的餐厅。
-
在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; }
}
}
MongoDB设置
尽管它不会是我们数据库中的一个文档,但我们需要一个模型类来存储与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,但在这里这是不必要的,因为我们通过在类上使用属性指定了集合。
将连接字符串和数据库详细信息添加到 appsettings
早些时候,我们创建了一个MongoDBSettings模型,现在我们需要将属性映射到的值添加到我们的appsettings.
-
在appsettings.json和appsettings.Development.json中,添加以下新的部分:
"MongoDBSettings": { "AtlasURI": "mongodb+srv://<username>:<password>@<url>", "DatabaseName": "restaurants" }
-
用从Atlas获取的自己的连接字符串替换Atlas URI。
更新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
接下来是我们的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
我们还想要一个视图模型,它可以用于我们稍后添加的Add视图。
-
在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
稍后,我们将在视图中添加对模型和视图模型的引用。为了让应用程序知道它们是什么,我们需要在Views文件夹中的_ViewImports.cshtml文件中添加对它们的引用。
里面已经有一些引用,包括TagHelpers,所以我们想要添加对我们的.Models和.ViewModels文件夹的引用。所以文件的开头应该看起来像这样:
@using RestRes
@using RestRes.Models
@using RestRes.ViewModels
创建控制器
现在我们已经有了后端实现和我们将要引用的视图模型,我们可以开始着手前端了。我们将创建两个控制器:一个用于Restaurant,一个用于Reservation。
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非常相似,但它同时引用了餐厅和预定服务,因为我们需要将餐厅与预定关联起来。这是因为当前EF Core提供商不支持实体间的关系,所以我们可以用另一种方式关联实体。
-
再创建一个名为ReservationController.cs的空MVC控制器文件。
-
粘贴以下代码:
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 视图 – 空白。将视图命名为 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 子文件夹内,添加一个名为 Add.cshtml 的新空白 Razor 视图。
-
添加以下代码:
@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>
}
添加预订
添加预订是下一步。
-
创建一个名为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>
更新导航栏
最后要添加的是更新应用程序的导航栏,这样我们就可以轻松地在餐厅和预订之间切换。
导航到Views/Shared/_Layout.cshtml
文件。找到具有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>
测试我们的应用程序
我们现在有一个使用新的MongoDB提供程序 for EF Core的功能性应用程序。现在是测试它并访问我们的端点以确保它一切正常的时候了。
在终端中运行以下命令:
dotnet run
编辑餐厅并添加预订。然后您可以导航到MongoDB Atlas数据库页面,查看您的更改是否已反映在数据库中。
高级MongoDB操作:Atlas搜索和向量搜索
EF Core提供程序基于MongoDB C#驱动程序构建。由于我们在创建DbContext时已经可以访问MongoClient,这使得我们可以执行如Atlas搜索和向量搜索等高级MongoDB操作。这些功能通过提供强大的搜索功能,同时仍然利用熟悉的EF Core框架,增强了应用程序的能力。
Atlas搜索
Atlas Search是MongoDB Atlas提供的一款全文搜索引擎。它允许您在MongoDB数据上运行复杂的搜索查询。使用Atlas Search,您可以实现如自动补全、分面搜索和基于相关性的排序等功能。
要使用EF Core提供程序进行Atlas Search,请按照以下步骤操作:
-
在MongoDB Atlas中设置索引:
-
前往您的MongoDB Atlas集群。
-
导航到“搜索”标签,并在您的集合上创建一个新的索引。定义您希望使其可搜索的字段。
-
-
在您的模型中定义可搜索字段:在您的C#模型中,确保正确定义您想要搜索的字段。以下是一个产品模型定义的示例。
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
("Products"); var searchResult = collection.Aggregate() .Match(Builders .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的高级功能,您可以构建既强大又灵活的应用程序,充分利用EF Core的结构化数据访问模式和MongoDB Atlas的强大搜索能力。
Source:
https://www.freecodecamp.org/news/using-entity-framework-core-with-mongodb/