ABP VNext + MongoDB 數據存儲:多模型支持與 NoSQL 擴展

🚀 ABP VNext + MongoDB 數據存儲:多模型支持與 NoSQL 擴展(生產級實踐)


目錄

  • 🚀 ABP VNext + MongoDB 數據存儲:多模型支持與 NoSQL 擴展(生產級實踐)
    • 🎯 引言
    • 🧰 環境與依賴
      • ?? appsettings.json
    • 🏗? 架構概述
    • 🤖 集成與配置
      • 📑 模塊注冊
      • 📘 DbContext 定義
    • 📦 自定義倉儲實現
    • 🔐 事務處理與一致性
      • 🔄 UnitOfWork 流程
    • 🗺? 分片與模型設計
      • 🔑 Shard Key 評估
      • 🏗? 多模型建模
    • 🚀 性能優化指南
      • 📈 索引創建
      • ? 批量寫入
    • 📊 監控與可觀測性
      • 🐢 慢查詢檢測(CommandSucceededEvent)
      • 🌐 Application Insights
    • 🛠? Controller 全 CRUD 示例
    • 🧪 單元測試示例(xUnit + Mongo2Go + DI)
    • 📚 附錄


🎯 引言

在高并發、快速迭代的業務環境中,傳統 RDBMS 因結構僵硬、事務開銷大而難以應對。MongoDB 以其靈活文檔模型、高吞吐與分布式能力,成為 ABP 應用的理想補充。本文將示范如何在 ABP VNext 中生產級地集成 MongoDB——從配置、DI、倉儲,到事務、多模型設計與監控全覆蓋。

💬 業務痛點

  • 頻繁迭代導致表結構變更成本高
  • 大規模寫入時事務與鎖競爭瓶頸明顯
  • 多租戶隔離需高擴展性

🧰 環境與依賴

  • 🖥? .NET 8
  • 📦 ABP v6+
  • 🌐 MongoDB Server 6.x(Replica Set / Sharded Cluster)
  • 📦 NuGet 包
    • MongoDB.Driver
    • Volo.Abp.MongoDB

?? appsettings.json

{"ConnectionStrings": {"MongoDb": "mongodb://localhost:27017/?maxPoolSize=200&minPoolSize=50"},"MongoDb": {"DatabaseName": "MyProjectDb"}
}

🏗? 架構概述

📩 HTTP 請求
🔧 Application Service
📦 Domain Service
📚 MongoRepository
🗄? MyMongoDbContext
🌐 MongoDB Server

🤖 集成與配置

📑 模塊注冊

public override void PreConfigureServices(ServiceConfigurationContext context)
{Configure<AbpMongoDbContextOptions>(options =>{options.ConnectionStringName = "MongoDb";});
}public override void ConfigureServices(ServiceConfigurationContext context)
{context.Services.AddMongoDbContext<MyMongoDbContext>(builder =>{// includeAllEntities: false 僅為聚合根生成倉儲builder.AddDefaultRepositories(includeAllEntities: false);});
}

💡 可根據項目需要,將 includeAllEntities 設置為 truefalse

📘 DbContext 定義

[ConnectionStringName("MongoDb")]
[MultiTenant]
public class MyMongoDbContext : AbpMongoDbContext
{public IMongoCollection<Order> Orders => Database.GetCollection<Order>("Orders");public IMongoCollection<Address> Addresses => Database.GetCollection<Address>("Addresses");public MyMongoDbContext(IAbpMongoDbContextOptions<MyMongoDbContext> options): base(options) { }
}
  • 建議:在模塊 PreConfigureServices 注入 ICurrentTenant 控制數據庫路由。

📦 自定義倉儲實現

public interface IMongoRepository<TEntity, TKey> : IRepository<TEntity, TKey>where TEntity : class, IEntity<TKey>
{Task BulkInsertAsync(IEnumerable<TEntity> entities, bool isOrdered = false);Task<IEnumerable<TResult>> AggregateLookupAsync<TForeign, TResult>(Expression<Func<TEntity, object>> localField,Expression<Func<TForeign, object>> foreignField,PipelineDefinition<TEntity, TResult> pipeline);
}public class MongoRepository<TEntity, TKey>: MongoDbRepository<MyMongoDbContext, TEntity, TKey>, IMongoRepository<TEntity, TKey>where TEntity : class, IEntity<TKey>
{private readonly IMongoCollection<TEntity> _collection;public MongoRepository(IDbContextProvider<MyMongoDbContext> dbContextProvider): base(dbContextProvider){_collection = dbContextProvider.GetDbContext().Database.GetCollection<TEntity>(typeof(TEntity).Name);}public async Task BulkInsertAsync(IEnumerable<TEntity> entities, bool isOrdered = false){var models = entities.Select(e => new InsertOneModel<TEntity>(e));await _collection.BulkWriteAsync(models, new BulkWriteOptions { IsOrdered = isOrdered });}public async Task<IEnumerable<TResult>> AggregateLookupAsync<TForeign, TResult>(Expression<Func<TEntity, object>> localField,Expression<Func<TForeign, object>> foreignField,PipelineDefinition<TEntity, TResult> pipeline){return await _collection.Aggregate(pipeline).ToListAsync();}
}

🔐 事務處理與一致性

🔄 UnitOfWork 流程

Controller AppService UnitOfWork Repository CreateAsync(input) BeginTransaction() InsertAsync(order) Acknowledged Commit() Completed Return OrderDto Controller AppService UnitOfWork Repository
public class OrderAppService : ApplicationService, IOrderAppService
{private readonly IMongoRepository<Order, Guid> _orderRepository;public OrderAppService(IMongoRepository<Order, Guid> orderRepository)=> _orderRepository = orderRepository;[UnitOfWork]public async Task<OrderDto> CreateAsync(CreateOrderDto input){var order = ObjectMapper.Map<Order>(input);await _orderRepository.InsertAsync(order);return ObjectMapper.Map<OrderDto>(order);}
}

🗺? 分片與模型設計

🔑 Shard Key 評估

sh.shardCollection("MyProjectDb.Orders", { CustomerId: 1, CreatedAt: 1 });

?? 復合鍵示例,可有效避免單一熱點。

🏗? 多模型建模

引用模型
AddressId
Order
Address 集合
嵌入式
Address 嵌入
Order
// 示例 $lookup 聚合
var results = await _context.Orders.Aggregate().Lookup<Address, LookupResult>(_context.Addresses,o => o.AddressId,a => a.Id,result => result.Addresses).ToListAsync();

🚀 性能優化指南

📈 索引創建

var orderCollection = context.Database.GetCollection<Order>("Orders");
await orderCollection.Indexes.CreateManyAsync(new[]
{new CreateIndexModel<Order>(Builders<Order>.IndexKeys.Ascending(o => o.CustomerId)),new CreateIndexModel<Order>(Builders<Order>.IndexKeys.Descending(o => o.CreatedAt))
});

? 批量寫入

await repository.BulkInsertAsync(largeOrderList, isOrdered: false);

🛠? 捕獲 BulkWriteException 并重試或補償處理。


📊 監控與可觀測性

🐢 慢查詢檢測(CommandSucceededEvent)

Configure<AbpMongoOptions>(options =>
{options.ClusterConfigurator = cb =>{cb.Subscribe<CommandSucceededEvent>(e =>{if (e.CommandName == "find" && e.Duration > TimeSpan.FromMilliseconds(100)){Logger.LogWarning("🐢 Slow MongoDB query: {Command}", e.Command);}});};
});

🌐 Application Insights

services.AddApplicationInsightsTelemetry();
var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();
// 示例上報連接池使用率
var poolUsage = /* 讀取連接池狀態 */;
telemetryClient.TrackMetric("mongo.connectionPoolUsage", poolUsage);

🛠? Controller 全 CRUD 示例

[ApiController]
[Route("api/orders")]
public class OrdersController : AbpController
{private readonly IOrderAppService _service;public OrdersController(IOrderAppService service) => _service = service;[HttpPost][ProducesResponseType(typeof(OrderDto), 201)]public async Task<OrderDto> Create(CreateOrderDto input){return await _service.CreateAsync(input);}[HttpGet("{id}")][ProducesResponseType(typeof(OrderDto), 200)][ProducesResponseType(404)]public Task<OrderDto> Get(Guid id) => _service.GetAsync(id);[HttpPut("{id}")][ProducesResponseType(typeof(OrderDto), 200)]public Task<OrderDto> Update(Guid id, UpdateOrderDto input){input.Id = id;return _service.UpdateAsync(input);}[HttpDelete("{id}")][ProducesResponseType(204)]public Task Delete(Guid id) => _service.DeleteAsync(id);
}

🧪 單元測試示例(xUnit + Mongo2Go + DI)

public class OrderRepositoryTests : IClassFixture<ServiceFixture>
{private readonly IMongoRepository<Order, Guid> _repository;public OrderRepositoryTests(ServiceFixture fixture){_repository = fixture.ServiceProvider.GetRequiredService<IMongoRepository<Order, Guid>>();}[Fact]public async Task BulkInsert_Should_Insert_All_Orders(){var orders = Enumerable.Range(1, 10).Select(i => new Order { Id = Guid.NewGuid(), CustomerId = $"C{i}" }).ToList();await _repository.BulkInsertAsync(orders);var count = await _repository.GetCountAsync();Assert.Equal(10, count);}[Fact]public async Task Update_Should_Modify_Order(){var order = await _repository.InsertAsync(new Order { Id = Guid.NewGuid(), CustomerId = "C0" });order.CustomerId = "C0-Updated";await _repository.UpdateAsync(order);var fetched = await _repository.GetAsync(order.Id);Assert.Equal("C0-Updated", fetched.CustomerId);}[Fact]public async Task Delete_Should_Remove_Order(){var order = await _repository.InsertAsync(new Order { Id = Guid.NewGuid(), CustomerId = "C1" });await _repository.DeleteAsync(order.Id);await Assert.ThrowsAsync<EntityNotFoundException>(() => _repository.GetAsync(order.Id));}
}public class ServiceFixture : IDisposable
{public ServiceProvider ServiceProvider { get; }public ServiceFixture(){var runner = MongoDbRunner.Start();var services = new ServiceCollection();services.Configure<AbpMongoDbContextOptions<MyMongoDbContext>>(options =>{options.ConnectionStringName = "MongoDb";});services.AddMongoDbContext<MyMongoDbContext>(builder =>{builder.AddDefaultRepositories(includeAllEntities: false);});services.AddTransient(typeof(IMongoRepository<,>), typeof(MongoRepository<,>));services.AddSingleton(runner);ServiceProvider = services.BuildServiceProvider();}public void Dispose(){var runner = ServiceProvider.GetRequiredService<MongoDbRunner>();runner.Dispose();}
}

📚 附錄

  • ABP 官方文檔:https://docs.abp.io
  • MongoDB 索引指南:https://www.mongodb.com/docs/manual/indexes/
  • Mongo2Go:https://github.com/Mongo2Go/Mongo2Go

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/909938.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909938.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909938.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Cursor Rules 的核心定位與作用 DevOps是

Cursor Rules 是 AI 編程工具 Cursor IDE 中的核心功能&#xff0c;用于約束 AI 生成代碼的行為&#xff0c;確保其符合項目規范、編碼風格或特定技術需求。它本質上是一套持久化、可復用的指令集&#xff0c;會動態插入到 AI 模型的上下文提示中&#xff0c;指導其生成代碼的邏…

Qt事件處理機制

事件的概念 在Qt中&#xff0c;以事件驅動UI工具集&#xff0c;包括信號和槽都依賴于Qt的事件處理機制。通常事件是由窗口系統或Qt自身產生的&#xff0c;用以響應所發生的各類事情。如&#xff1a;用戶按下并釋放鍵盤或鼠標、窗口縮放后重繪、定時器到時等。如下圖&#xff1…

【慧游魯博】【11】小程序端·游覽畫卷修改·支持圖片url格式·結合圖床上傳和加載·數據對接

文章目錄 需求修改細節前端主要修改點說明&#xff1a;前端傳遞格式 后端ArtifactItem 類&#xff1a;ScrollServiceImpl 類&#xff1a;修改 InfoPanel 結構重構 ScrollHorizontalRollComposer修改后的 ScrollHorizontalRollComposer移除冗余代碼修改總結 數據流圖片格式兼容性…

攻克SQL審核“最后堡壘”!PawSQL首發T-SQL存儲過程深度優化引擎

為什么存儲過程審核那么難&#xff1f; 存儲過程將數據操作邏輯固化在數據庫層&#xff0c;一次編譯、多次執行&#xff0c;既能大幅提升性能&#xff0c;也能通過權限隔離增強安全。然而&#xff0c;正因其邏輯復雜、分支眾多&#xff0c;存儲過程內部的 SQL 審核與優化常常成…

計算機網絡零基礎完全指南

目錄 ?? 什么是計算機網絡 生活中的類比 計算機網絡的本質 網絡的發展歷程 ?? 網絡IP詳解(重點) 1. IP地址是什么? 生活例子:IP地址就像門牌號 IP地址的格式 IP地址的二進制表示 2. IP地址的分類詳解 A類地址(大型網絡) B類地址(中型網絡) C類地址(小…

DL___線性神經網絡

1&#xff09;回歸&#xff08;regression&#xff09;是能為一個或多個自變量與因變量之間關系建模的一類方法。 在自然科學和社會科學領域&#xff0c;回歸經常用來表示輸入和輸出之間的關系。 2&#xff09;一般回歸是和預測有關&#xff0c;比如預測價格(房屋&#xff0c;…

WSL2安裝與使用(USB、GPU、虛擬機、圖形界面)

文章目錄 前言WSL2安裝&#xff08;手動安裝&#xff09;WSL2基礎使用VS Code與WSL2配合使用連接USB設備WSL2中使用GPU&#xff08;RTX5060Ti 16G&#xff09;與虛擬機兼容使用&#xff08;Virtual Box&#xff09;圖形與桌面環境WSL消失&#xff08;災難性故障&#xff09;問題…

uni-app項目實戰筆記16--實現頭部導航欄效果

先來看效果&#xff1a; 要求&#xff1a;頂部導航欄要始終固定在上方&#xff0c;不隨頁面上下拖動而消失。 代碼實現&#xff1a; 1.定義一個自定義導航欄組件&#xff1a;custom-nav-bar.vue&#xff0c;并寫入如下代碼&#xff1a; <template><view class"…

web3.js 核心包及子模塊

. 核心包 (web3) 功能:提供基礎連接、工具函數和核心功能。 包含子模塊: web3.eth - 以太坊區塊鏈交互 web3.utils - 輔助工具函數 web3.shh - Whisper 協議(已廢棄) web3.bzz - Swarm 去中心化存儲(已廢棄) web3.net - 網絡相關功能 web3.contract - 智能合約交互 web3.…

訓練檢測之前的視頻抽幀

接下來安裝pytorch Previous PyTorch Versions 視頻抽幀 import cv2def extract_frames(video_path, output_folder, frame_rate1):"""從視頻中抽取幀。:param video_path: 視頻文件的路徑:param output_folder: 存儲幀的文件夾路徑:param frame_rate: 抽取的…

智能家居HA篇 二、配置Home Assistant并實現外部訪問

智能家居HA篇 一、Win10 VM虛擬機安裝 Home Assistant 手把手教學 二、通過Cpolar配置Home Assistant并實現外部訪問 文章目錄 智能家居HA篇前言一、內網穿透工具&#xff08;cpolar&#xff09;二、映射HA端口1.訪問cpolar儀表2.創建賬號并登錄3.創建隧道 三、HA設置及公網訪…

day09——Java基礎項目(ATM系統)

文章目錄 Java項目實戰&#xff1a;手把手開發ATM銀行系統&#xff08;附完整源碼&#xff09;一、系統架構設計1. 三層架構模型2. 核心數據結構 二、核心功能實現1. 開戶功能&#xff08;含唯一卡號生成&#xff09;2. 登錄安全驗證3. 存取款業務4. 安全轉賬實現 三、賬戶安全…

計算機網絡:(五)信道復用技術,數字傳輸系統,寬帶接入技術

計算機網絡&#xff1a;&#xff08;五&#xff09;信道復用技術&#xff0c;數字傳輸系統&#xff0c;寬帶接入技術 前言一、信道復用技術1. 為什么需要復用技術&#xff1f;2. 頻分復用&#xff08;FDM&#xff09;3. 時分復用&#xff08;TDM&#xff09;4. 統計時分復用&am…

【期末總結】計算機網絡

【期末總結】計算機網絡 參考鏈接&#xff1a;計算機網絡知識點全面總結&#xff08;有這一篇就夠了&#xff01;&#xff01;&#xff01;&#xff09;-CSDN博客 一.概述 1.1 計算機網絡的分類 按照網絡的作用范圍&#xff1a;廣域網&#xff08;WAN&#xff09;、城域網&a…

React學習001-創建 React 應用

React學習001-創建 React 應用 1、安裝node.js2、安裝構建工具2.1 核心特性2.2 性能對比??2.3 適用場景?? 3、創建應用4、項目啟動參考文章 1、安裝node.js 這里建議安裝nvm多版本管理node.js&#xff0c;想用哪個版本&#xff0c;一條命令即可~ 多版本管理node.js 2、安…

(cvpr2025) Adaptive Rectangular Convolution for Remote Sensing Pansharpening

論文&#xff1a;(cvpr2025) Adaptive Rectangular Convolution for Remote Sensing Pansharpening 代碼&#xff1a;https://github.com/WangXueyang-uestc/ARConv.git 這個論文研究的是全色與多光譜圖像的融合。作者認為現有的基于CNN的方法中&#xff0c;傳統的卷積存在兩個…

【圖像處理入門】7. 特征描述子:從LBP到HOG的特征提取之道

摘要 特征描述子是圖像處理中提取圖像本質信息的關鍵工具。本文將深入講解局部二值模式(LBP)與方向梯度直方圖(HOG)兩種經典特征描述子的原理、實現方法及應用場景。結合OpenCV代碼示例,展示如何利用LBP提取紋理特征、使用HOG進行目標檢測,幫助讀者掌握從圖像中提取有效…

AI 應用開發的‘核心樞紐’:Dify、Coze、n8n、FastGPT、MaxKB、RAGFlow 等六大平臺全面對決

在人工智能與自動化流程日益普及的當下&#xff0c;各類平臺如雨后春筍般涌現&#xff0c;成為構建智能應用與自動化工作流的 “核心樞紐”。其中&#xff0c;Dify、Coze、n8n、FastGPT、MaxKB、RAGFlow 備受矚目&#xff0c;它們各自具備獨特的功能與優勢&#xff0c;適用于不…

RV1126+OPENCV對視頻流單獨進行視頻膨脹/腐蝕操作

一.RV1126OPENCV對視頻流進行視頻膨脹操作的大體流程圖 思路&#xff1a;初始化VI與VENC模塊&#xff0c;之后開啟兩個線程&#xff0c;一個線程從VI模塊獲取視頻流數據&#xff0c;用Opencv的Mat將其轉成Mat矩陣之后進行用dilate膨脹&#xff0c;將膨脹之后的視頻數據用send函…