当前位置: 首页 > news >正文

【后端】.NET Core API框架搭建(6) --配置使用MongoDB

        

目录

1.添加包

2. 连接配置

        2.1.链接字符串

        2.2.连接类

3.仓储配置

        3.1.仓储实现

         3.2.仓储接口

4.获取配置和注册

4.1.添加配置获取方法

        4.2.注册 

5.常规使用案例

        5.1实体

        5.2.实现

        5.3.接口

        5.4.控制器


        NET Core 应用程序中使用 MongoDB 有许多好处,尤其是在处理大规模数据、需要高灵活性和扩展性的场景下。

1.添加包

        添加 MongoDB.Driver 包。

2. 连接配置

        2.1.连接字符串

        dbsettings.json文件添加 MongoDB连接配置

//MongoDB配置
"MongoDBSettings": {"MongoConnStr": "mongodb://root:密码@iP地址:Mongo端口","DatabaseName": "数据库名称"
},

        2.2.连接类

namespace Frame3_DataRepository.MongoRepository
{/// <summary>/// Mongo配置获取/// </summary>public class MongoOptions{/// <summary>/// 连接地址/// </summary>public string MongoConnStr { get; set; }/// <summary>/// 连接数据库/// </summary>public string DatabaseName { get; set; }}
}

        案例如下

3.仓储配置

        3.1.仓储实现

        为MongoDB添加仓储方便使用。

using MongoDB.Bson;
using MongoDB.Driver;
using System.Linq.Expressions;namespace Frame3_DataRepository.MongoRepository
{/// <summary>/// 泛型MongoDB仓储实现类,实现IMongoRepository<T>接口,约束T必须是class类型/// </summary>/// <typeparam name="T"></typeparam>public class MongoRepository<T> : IMongoRepository<T> where T : class{// 私有字段,存储MongoDB集合对象private readonly IMongoCollection<T> _collection;/// <summary>/// 构造函数,通过依赖注入初始化/// </summary>/// <param name="database">Mongo数据库实例</param>/// <param name="collectionName">集合名称(可选,默认为类型名称)</param>public MongoRepository(IMongoDatabase database, string collectionName = null){// 获取或创建集合:如果collectionName为null则使用类型名称作为集合名_collection = database.GetCollection<T>(collectionName ?? typeof(T).Name);}#region 基本CRUD操作/// <summary>/// 插入单个文档/// </summary>/// <param name="document">要插入的文档</param>/// <returns>受影响的行数(1表示成功,0表示失败)</returns>public async Task<int> InsertAsync(T document){try{// 异步插入单个文档await _collection.InsertOneAsync(document);return 1; // 插入单个文档总是返回1表示成功}catch{return 0; // 插入失败返回0}}/// <summary>/// 批量插入文档/// </summary>/// <param name="documents">要插入的文档集合</param>/// <returns>实际插入的文档数量</returns>public async Task<int> InsertAsync(IEnumerable<T> documents){try{// 转换为列表以避免多次枚举var docsList = documents.ToList();// 如果集合为空则直接返回0if (!docsList.Any()){return 0;}// 异步批量插入文档await _collection.InsertManyAsync(docsList);// 返回实际插入的文档数量return docsList.Count;}catch{return 0; // 插入失败返回0}}/// <summary>/// 根据ID获取文档/// </summary>/// <param name="id">文档ID字符串</param>/// <returns>找到的文档或默认值</returns>public async Task<T> GetByIdAsync(string id){try{// 构建ID过滤器(MongoDB默认使用"_id"字段)var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));// 异步查找并返回第一个匹配的文档return await _collection.Find(filter).FirstOrDefaultAsync();}catch{return default; // 出错返回默认值}}/// <summary>/// 获取所有文档/// </summary>/// <returns>所有文档列表或默认值</returns>public async Task<List<T>> GetAllAsync(){try{// 使用空过滤器获取所有文档return await _collection.Find(_ => true).ToListAsync();}catch{return default; // 出错返回默认值}}/// <summary>/// 条件查询/// </summary>/// <param name="filter">LINQ表达式过滤器</param>/// <returns>匹配条件的文档集合</returns>public async Task<IEnumerable<T>> FindByConditionAsync(Expression<Func<T, bool>> filter){try{// 使用表达式过滤器查询文档return await _collection.Find(filter).ToListAsync();}catch{return default; // 出错返回默认值}}/// <summary>/// 更新单个文档/// </summary>/// <param name="filter">查询过滤器</param>/// <param name="update">更新定义</param>/// <returns>实际修改的文档数量</returns>public async Task<int> UpdateAsync(Expression<Func<T, bool>> filter, UpdateDefinition<T> update){try{// 异步更新单个文档var result = await _collection.UpdateOneAsync(filter, update);// 返回实际修改的文档数量return (int)result.ModifiedCount;}catch{return 0; // 出错返回0}}/// <summary>/// 替换整个文档/// </summary>/// <param name="filter">查询过滤器</param>/// <param name="replacement">替换文档</param>/// <returns>实际修改的文档数量</returns>public async Task<int> UpdateAsync(Expression<Func<T, bool>> filter, T replacement){try{// 异步替换整个文档var result = await _collection.ReplaceOneAsync(filter, replacement);// 返回实际修改的文档数量return (int)result.ModifiedCount;}catch{return 0; // 出错返回0}}/// <summary>/// 删除单个文档/// </summary>/// <param name="filter">查询过滤器</param>/// <returns>实际删除的文档数量</returns>public async Task<int> DeleteAsync(Expression<Func<T, bool>> filter){try{// 异步删除单个文档var result = await _collection.DeleteOneAsync(filter);// 返回实际删除的文档数量return (int)result.DeletedCount;}catch{return 0; // 出错返回0}}/// <summary>/// 根据ID删除文档/// </summary>/// <param name="id">文档ID</param>/// <returns>实际删除的文档数量</returns>public async Task<int> DeleteByIdAsync(string id){try{// 构建ID过滤器var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));// 异步删除匹配的文档var result = await _collection.DeleteOneAsync(filter);// 返回实际删除的文档数量return (int)result.DeletedCount;}catch{return 0; // 出错返回0}}/// <summary>/// 批量删除文档/// </summary>/// <param name="filter">查询过滤器</param>/// <returns>实际删除的文档数量</returns>public async Task<int> DeleteManyAsync(Expression<Func<T, bool>> filter){try{// 异步删除多个文档var result = await _collection.DeleteManyAsync(filter);// 返回实际删除的文档数量return (int)result.DeletedCount;}catch{return 0; // 出错返回0}}#endregion#region 高级操作/// <summary>/// 分页查询/// </summary>/// <param name="filter">查询过滤器</param>/// <param name="pageNumber">页码</param>/// <param name="pageSize">每页大小</param>/// <param name="sort">排序定义(可选)</param>/// <returns>包含数据和总数的元组</returns>public async Task<(List<T> Data, int Total)> PaginateAsync(Expression<Func<T, bool>> filter, int pageNumber, int pageSize, SortDefinition<T> sort = null){try{// 获取匹配条件的文档总数var count = (int)await _collection.CountDocumentsAsync(filter);// 构建基础查询var query = _collection.Find(filter);// 如果提供了排序条件,则应用排序if (sort != null){query = query.Sort(sort);}// 执行分页查询:跳过前面的记录,限制返回数量var data = await query.Skip((pageNumber - 1) * pageSize).Limit(pageSize).ToListAsync();// 返回数据和总数return (data, count);}catch{return (null, 0); // 出错返回空数据和0总数}}/// <summary>/// 聚合查询/// </summary>/// <typeparam name="TResult">结果类型</typeparam>/// <param name="pipeline">聚合管道定义</param>/// <returns>聚合结果集合</returns>public async Task<IEnumerable<TResult>> AggregateAsync<TResult>(PipelineDefinition<T, TResult> pipeline){// 异步执行聚合管道并返回结果列表return await _collection.Aggregate(pipeline).ToListAsync();}/// <summary>/// 创建索引/// </summary>/// <param name="keys">索引键定义</param>/// <param name="options">索引选项(可选)</param>/// <returns>创建的索引名称</returns>public async Task<string> CreateIndexAsync(IndexKeysDefinition<T> keys, CreateIndexOptions options = null){// 异步创建索引并返回索引名称return await _collection.Indexes.CreateOneAsync(new CreateIndexModel<T>(keys, options));}/// <summary>/// 批量操作/// </summary>/// <param name="requests">批量写操作模型集合</param>/// <returns>批量操作结果</returns>public async Task<BulkWriteResult<T>> BulkWriteAsync(IEnumerable<WriteModel<T>> requests){// 异步执行批量写操作return await _collection.BulkWriteAsync(requests);}/// <summary>/// 文档计数/// </summary>/// <param name="filter">查询过滤器(可选)</param>/// <returns>匹配条件的文档数量</returns>public async Task<long> CountAsync(Expression<Func<T, bool>> filter = null){// 根据是否提供过滤器返回相应计数return filter == null? await _collection.CountDocumentsAsync(_ => true)  // 无过滤器时计算所有文档: await _collection.CountDocumentsAsync(filter);   // 有过滤器时计算匹配文档}#endregion#region 事务支持/// <summary>/// 执行事务操作/// </summary>/// <param name="actions">要在事务中执行的操作</param>public async Task ExecuteInTransactionAsync(Func<IClientSessionHandle, IMongoCollection<T>, Task> actions){// 创建会话using var session = await _collection.Database.Client.StartSessionAsync();// 开始事务session.StartTransaction();try{// 执行用户定义的操作await actions(session, _collection);// 提交事务await session.CommitTransactionAsync();}catch{// 出错时中止事务await session.AbortTransactionAsync();throw; // 重新抛出异常}}#endregion}
}

        案例如下 

         3.2.仓储接口

        方便使用仓储给所有实现加接口

using MongoDB.Driver;
using System.Linq.Expressions;namespace Frame3_DataRepository.MongoRepository
{public interface IMongoRepository<T> where T : class{/// <summary>/// 插入文档/// </summary>/// <param name="document"></param>/// <returns></returns>Task<int> InsertAsync(T document);/// <summary>/// 批量插入文档/// </summary>Task<int> InsertAsync(IEnumerable<T> documents);/// <summary>/// 根据ID获取文档/// </summary>Task<T> GetByIdAsync(string id);/// <summary>/// 获取所有文档/// </summary>Task<List<T>> GetAllAsync();/// <summary>/// 条件查询/// </summary>Task<IEnumerable<T>> FindByConditionAsync(Expression<Func<T, bool>> filter);/// <summary>/// 更新单个文档/// </summary>Task<int> UpdateAsync(Expression<Func<T, bool>> filter, UpdateDefinition<T> update);/// <summary>/// 替换整个文档/// </summary>Task<int> UpdateAsync(Expression<Func<T, bool>> filter, T replacement);/// <summary>/// 删除单个文档/// </summary>Task<int> DeleteAsync(Expression<Func<T, bool>> filter);/// <summary>/// 根据ID删除文档/// </summary>Task<int> DeleteByIdAsync(string id);/// <summary>/// 批量删除文档/// </summary>Task<int> DeleteManyAsync(Expression<Func<T, bool>> filter);/// <summary>/// 分页查询/// </summary>Task<(List<T> Data, int Total)> PaginateAsync(Expression<Func<T, bool>> filter, int pageNumber, int pageSize, SortDefinition<T> sort = null);/// <summary>/// 聚合查询/// </summary>Task<IEnumerable<TResult>> AggregateAsync<TResult>(PipelineDefinition<T, TResult> pipeline);/// <summary>/// 创建索引/// </summary>Task<string> CreateIndexAsync(IndexKeysDefinition<T> keys, CreateIndexOptions options = null);/// <summary>/// 批量操作/// </summary>Task<BulkWriteResult<T>> BulkWriteAsync(IEnumerable<WriteModel<T>> requests);/// <summary>/// 文档计数/// </summary>Task<long> CountAsync(Expression<Func<T, bool>> filter = null);/// <summary>/// 执行事务操作/// </summary>Task ExecuteInTransactionAsync(Func<IClientSessionHandle, IMongoCollection<T>, Task> actions);}
}

        案例如下

4.获取配置和注册

        获取连接字符串、注册Mongo实例和仓储

4.1.添加配置获取方法

using Microsoft.Extensions.Configuration;namespace Frame4_LibraryCore.BaseConfig
{/// <summary>/// 全局配置/// </summary>public static class Config{/// <summary>/// 从指定的 JSON 配置文件中读取配置,并反序列化为指定类型/// </summary>/// <typeparam name="T">目标配置类型(如 RedisSettings、DatabaseSettings 等)</typeparam>/// <param name="fileName">JSON 配置文件名(如 "appsettings.json")</param>/// <param name="sessions">配置节点名称(如 "RedisSettings")</param>/// <returns>返回绑定后的强类型配置对象</returns>public static T GetSetting<T>(string fileName, string sessions){//创建 ConfigurationBuilder 实例,用于构建配置var builder = new ConfigurationBuilder()//设置配置文件的基础路径为当前程序运行目录.SetBasePath(Directory.GetCurrentDirectory())//添加 JSON 文件作为配置源://- fileName: 指定要加载的 JSON 文件//- optional: false 表示文件必须存在,否则抛出异常//- reloadOnChange: true 表示文件修改时自动重新加载.AddJsonFile(fileName, optional: false, reloadOnChange: true);//构建配置对象(IConfigurationRoot)IConfigurationRoot config = builder.Build();//获取指定配置节点(sessions),并将其反序列化为类型 Tvar conn = config.GetSection(sessions).Get<T>();//返回反序列化后的配置对象return conn;}}
}

        案例如下 

 

        4.2.注册 

        添加注册方法方便程序注册

using Frame4_LibraryCore.BaseConfig;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Driver;namespace Frame3_DataRepository.MongoRepository
{/// <summary>/// MongoDB仓储相关服务/// </summary>public static class MongoExtension{/// <summary>/// 扩展方法:向IServiceCollection添加MongoDB仓储相关服务/// </summary>/// <param name="services">服务集合</param>/// <returns>配置后的服务集合</returns>public static IServiceCollection AddMongoRepository(this IServiceCollection services){// 从配置文件"dbsettings.json"的"MongoDBSettings"节点获取MongoDB配置选项var mongoOptions = Config.GetSetting<MongoOptions>("dbsettings.json", "MongoDBSettings");// 注册IMongoClient为单例服务(因为MongoClient是线程安全的,适合单例)services.AddSingleton<IMongoClient>(sp => new MongoClient(mongoOptions.MongoConnStr));// 注册IMongoDatabase为作用域服务(每个请求一个实例)services.AddScoped(sp =>{// 从服务容器获取已注册的IMongoClient实例var client = sp.GetRequiredService<IMongoClient>();// 使用配置中的数据库名称获取数据库实例return client.GetDatabase(mongoOptions.DatabaseName);});// 注册泛型仓储接口和实现(IMongoRepository<>和MongoRepository<>)services.AddScoped(typeof(IMongoRepository<>), typeof(MongoRepository<>));// 返回配置好的服务集合以支持链式调用return services;}}
}

         案例如下

        新增好注册方法后即可在  Program 或 Startup 中注册。

//注册MongoDB服务
builder.Services.AddMongoRepository();

        案例如下 

5.常规使用案例

        下面是 实体、实现、接口和控制器的使用案例

        5.1实体

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;namespace Frame2_DataModel.MongoEntity.Product
{/// <summary>/// 产品表-Mongo/// </summary>public class ProductEntity{[BsonId] // 标记这是 MongoDB 的 _id 字段[BsonRepresentation(BsonType.ObjectId)] // 表示该字段使用 ObjectId 类型public string Id { get; set; }/// <summary>/// 产品名称/// </summary>public string ProductName { get; set; }/// <summary>/// 价格/// </summary>public decimal Price { get; set; }/// <summary>/// 库存/// </summary>public int Stock { get; set; }}
}

        案例如下

 

        5.2.实现

using Frame_Service.IService.Product;
using Frame1_Service.IService.Product;
using Frame2_DataModel.MongoEntity.Product;
using Frame3_DataRepository.MongoRepository;
using Frame6_LibraryUtility;namespace Frame1_Service.Service.Product
{/// <summary>/// MongoDB测试实现/// </summary>public class ProductSvr : BaseService, IProductSvr{/// <summary>/// 产品-Mongo/// </summary>private readonly IMongoRepository<ProductEntity> _productSvr;/// <summary>/// 构造函数/// </summary>public ProductSvr(IMongoRepository<ProductEntity> productSvr){_productSvr = productSvr;}#region 查询数据/// <summary>/// 获取所有产品/// </summary>/// <returns></returns>public async Task<ResultModel<List<ProductEntity>>> GetProductAll(){var result = new ResultModel<List<ProductEntity>>() { Data = null };var list = await _productSvr.GetAllAsync();result.Code = ResultCodeEnum.Success;result.Msg = "获取成功";result.Data = list;return result;}/// <summary>/// 根据Id获取产品/// </summary>/// <param name="id"></param>/// <returns></returns>public async Task<ResultModel<ProductEntity>> GetByIdProduct(string id){var result = new ResultModel<ProductEntity>() { Data = null };var list = await _productSvr.GetByIdAsync(id);result.Msg = "获取成功";result.Data = list;return result;}/// <summary>/// 获取所有产品-分页/// </summary>/// <param name="model"></param>/// <returns></returns>public async Task<ResultPageModel<List<ProductEntity>>> GetProductPageList(PageList model){var result = new ResultPageModel<List<ProductEntity>>() { Data = null };var (products, total) = await _productSvr.PaginateAsync(filter: p => true, pageNumber: model.PageIndex, pageSize: model.PageSize);result.TotalCount = total;result.PageIndex = model.PageIndex;result.PageSize = model.PageSize;result.Data = products;result.Msg = "获取成功";return result;}#endregion#region 修改数据/// <summary>/// 保存产品/// </summary>/// <param name="model"></param>/// <returns></returns>public async Task<ResultModel<int>> SaveProduct(ProductEntity model){var result = new ResultModel<int>() { Data = 0 };#region 数据校验if (model.IsEmpty()){result.Code = ResultCodeEnum.Error;result.Msg = "传参错误";return result;}#endregionint row = 0;if (model.Id.IsEmpty()){row = await _productSvr.InsertAsync(model);}else{row = await _productSvr.UpdateAsync(a => a.Id.Equals(model.Id), model);}if (row > 0){result.Code = ResultCodeEnum.Success;result.Msg = "操作成功";result.Data = row;}return result;}/// <summary>/// 根据Id删除产品/// </summary>/// <param name="id"></param>/// <returns></returns>public async Task<ResultModel<int>> RemoveProduct(string id){var result = new ResultModel<int>() { Data = 0 };int row = await _productSvr.DeleteByIdAsync(id);if (row > 0){result.Code = ResultCodeEnum.Success;result.Msg = "操作成功";result.Data = row;}return result;}#endregion}
}

        案例如下

        5.3.接口

using Frame2_DataModel.MongoEntity.Product;
using Frame6_LibraryUtility;namespace Frame1_Service.IService.Product
{/// <summary>/// MongoDB测试接口/// </summary>public interface IProductSvr{/// <summary>/// 获取所有产品/// </summary>/// <returns></returns>Task<ResultModel<List<ProductEntity>>> GetProductAll();/// <summary>/// 根据Id获取产品/// </summary>/// <param name="id"></param>/// <returns></returns>Task<ResultModel<ProductEntity>> GetByIdProduct(string id);/// <summary>/// 获取所有产品-分页/// </summary>/// <param name="model"></param>/// <returns></returns>Task<ResultPageModel<List<ProductEntity>>> GetProductPageList(PageList model);/// <summary>/// 保存产品/// </summary>/// <param name="model"></param>/// <returns></returns>Task<ResultModel<int>> SaveProduct(ProductEntity model);/// <summary>/// 根据Id删除产品/// </summary>/// <param name="id"></param>/// <returns></returns>Task<ResultModel<int>> RemoveProduct(string id);}
}

        案例如下

        5.4.控制器

using Frame1_Service.IService.Product;
using Frame2_DataModel.MongoEntity.Product;
using Frame4_LibraryCore.BaseConfig;
using Frame6_LibraryUtility;
using Microsoft.AspNetCore.Mvc;namespace DemoAPI.Controllers
{/// <summary>/// MongoDB测试控制器/// </summary>//[Authorize]// 保护整个控制器[Route("api/[controller]/[action]")]//标记路由地址规格[ApiController] // 标记该类为 API 控制器,启用一些默认的行为,如模型绑定、输入验证等[ApiExplorerSettings(GroupName = nameof(ApiVersionInfo.V1))]//设置控制器的API版本public class ProductController : BaseController{/// <summary>/// 产品/// </summary>private readonly IProductSvr _IProductSvr;/// <summary>/// 构造/// </summary>/// <param name="productSvr"></param>public ProductController(IProductSvr productSvr){_IProductSvr = productSvr;}/// <summary>/// 获取所有产品/// </summary>/// <returns></returns>[HttpGet]public async Task<ResultModel<List<ProductEntity>>> GetProductAll() => await _IProductSvr.GetProductAll();/// <summary>/// 根据Id获取产品/// </summary>/// <param name="id"></param>/// <returns></returns>[HttpGet]public async Task<ResultModel<ProductEntity>> GetByIdProduct(string id) => await _IProductSvr.GetByIdProduct(id);/// <summary>/// 获取所有产品-分页/// </summary>/// <param name="model"></param>/// <returns></returns>[HttpPost]public async Task<ResultPageModel<List<ProductEntity>>> GetProductPageList(PageList model) => await _IProductSvr.GetProductPageList(model);/// <summary>/// 保存产品/// </summary>/// <param name="model"></param>/// <returns></returns>[HttpPost]public async Task<ResultModel<int>> SaveProduct(ProductEntity model) => await _IProductSvr.SaveProduct(model);/// <summary>/// 根据Id删除产品/// </summary>/// <param name="id"></param>/// <returns></returns>[HttpGet]public async Task<ResultModel<int>> RemoveProduct(string id) => await _IProductSvr.RemoveProduct(id);}
}

        案例如下

http://www.dtcms.com/a/282281.html

相关文章:

  • 随机链表的复制数据结构oj题(力口138)
  • 数据结构--准备知识
  • 随机链表的复制数据结构oj题(CM11)
  • SOTI MobiControl vs EasyControl:MDM 解决方案对比 —— 理解差异与价值
  • batchnorm1d,layernorm,revin区别
  • 关于程序=数据结构+算法这句话最近的一些思考
  • 【数据结构】「栈」(顺序栈、共享栈、链栈)
  • iOS 抓包工具选择与配置指南 从零基础到高效调试的完整流程
  • 时序大模型为时序数据库带来的变革与机遇
  • Flutter 记录 使用ModalRoute获取参数
  • flutter app内跳转到其他安卓 app的方法
  • qt udp接收时 丢包
  • 安卓开发使用Android Studio配置flutter环境
  • 《Qt信号与槽机制》详解:从基础到实践
  • Flutter运行Android项目时显示java版本不兼容(Unsupported class file major version 65)的处理
  • 《Qt实战开发》:从计算器到音乐播放器的全栈实现指南
  • 7月16日作业
  • QOpenGLWidget自定义控件— 2D点云显示(支持平移、放缩、绘制网格)
  • 桥下的蓝色风景线
  • 数据库连接池调优以及常见问题
  • SSM框架学习——day3
  • 如何解决WordPress数据库表损坏导致的错误
  • Python 测试全景:单元测试、集成测试与端到端测试实战指南
  • 【收银系统源码】-适用于零售餐饮连锁多门店
  • Docker化Web服务部署全景指南:从基础服务器到企业级应用
  • VUE指令大全
  • 使用Node搭建一个直播服务器,实时直播当前桌面
  • WAMP允许远程访问
  • WAN技术
  • 基于 Python/PHP/Node.js 的淘宝 API 商品数据抓取开发教程