ASP.NET Core MongoDB:NoSQL数据库集成实战指南

ASP.NET Core MongoDB:NoSQL数据库集成实战指南

【免费下载链接】aspnetcore dotnet/aspnetcore: 是一个 ASP.NET Core 应用程序开发框架的官方 GitHub 仓库,它包含了 ASP.NET Core 的核心源代码和技术文档。适合用于 ASP.NET Core 应用程序开发,特别是对于那些需要深入了解 ASP.NET Core 框架实现和技术的场景。特点是 ASP.NET Core 官方仓库、核心源代码、技术文档。 【免费下载链接】aspnetcore 项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore

引言:为什么选择MongoDB与ASP.NET Core?

在现代Web应用开发中,数据存储方案的选择至关重要。传统的关系型数据库虽然成熟稳定,但在处理非结构化数据、高并发读写和海量数据存储方面存在局限性。MongoDB作为领先的NoSQL(非关系型数据库)解决方案,与ASP.NET Core的结合为开发者提供了强大的数据管理能力。

读完本文你将掌握:

  • MongoDB核心概念与ASP.NET Core集成原理
  • 官方MongoDB.Driver驱动程序的完整配置流程
  • 基于Repository模式的CRUD操作最佳实践
  • 高级查询、聚合管道和事务处理技巧
  • 性能优化与生产环境部署策略

一、环境准备与项目配置

1.1 安装必要依赖

首先通过NuGet包管理器安装MongoDB官方驱动程序:

<PackageReference Include="MongoDB.Driver" Version="2.19.0" />
<PackageReference Include="MongoDB.Driver.Core" Version="2.19.0" />
<PackageReference Include="MongoDB.Bson" Version="2.19.0" />

1.2 配置MongoDB连接字符串

appsettings.json中配置MongoDB连接信息:

{
  "MongoDBSettings": {
    "ConnectionString": "mongodb://localhost:27017",
    "DatabaseName": "AspNetCoreMongoDemo",
    "CollectionName": "Products"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

1.3 依赖注入配置

Program.cs中注册MongoDB服务:

using MongoDB.Driver;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

// 配置MongoDB设置
builder.Services.Configure<MongoDBSettings>(
    builder.Configuration.GetSection(nameof(MongoDBSettings)));

// 注册MongoDB客户端单例
builder.Services.AddSingleton<IMongoClient>(serviceProvider =>
{
    var settings = serviceProvider.GetRequiredService<IOptions<MongoDBSettings>>().Value;
    return new MongoClient(settings.ConnectionString);
});

// 注册数据库实例
builder.Services.AddScoped(serviceProvider =>
{
    var settings = serviceProvider.GetRequiredService<IOptions<MongoDBSettings>>().Value;
    var client = serviceProvider.GetRequiredService<IMongoClient>();
    return client.GetDatabase(settings.DatabaseName);
});

// 添加控制器服务
builder.Services.AddControllers();

二、数据模型设计

2.1 定义实体类

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

public class Product
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string? Id { get; set; }

    [BsonElement("name")]
    public required string Name { get; set; }

    [BsonElement("description")]
    public string? Description { get; set; }

    [BsonElement("price")]
    public decimal Price { get; set; }

    [BsonElement("category")]
    public required string Category { get; set; }

    [BsonElement("tags")]
    public List<string> Tags { get; set; } = new();

    [BsonElement("createdAt")]
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

    [BsonElement("updatedAt")]
    public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

// 配置类
public class MongoDBSettings
{
    public required string ConnectionString { get; set; }
    public required string DatabaseName { get; set; }
    public required string CollectionName { get; set; }
}

2.2 实体关系映射示意图

mermaid

三、Repository模式实现

3.1 定义通用Repository接口

public interface IRepository<T> where T : class
{
    Task<IEnumerable<T>> GetAllAsync();
    Task<T?> GetByIdAsync(string id);
    Task CreateAsync(T entity);
    Task UpdateAsync(string id, T entity);
    Task DeleteAsync(string id);
    Task<bool> ExistsAsync(string id);
}

3.2 MongoDB Repository实现

using MongoDB.Driver;

public class MongoRepository<T> : IRepository<T> where T : class
{
    private readonly IMongoCollection<T> _collection;

    public MongoRepository(IMongoDatabase database, string collectionName)
    {
        _collection = database.GetCollection<T>(collectionName);
    }

    public async Task<IEnumerable<T>> GetAllAsync()
    {
        return await _collection.Find(_ => true).ToListAsync();
    }

    public async Task<T?> GetByIdAsync(string id)
    {
        var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));
        return await _collection.Find(filter).FirstOrDefaultAsync();
    }

    public async Task CreateAsync(T entity)
    {
        await _collection.InsertOneAsync(entity);
    }

    public async Task UpdateAsync(string id, T entity)
    {
        var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));
        await _collection.ReplaceOneAsync(filter, entity);
    }

    public async Task DeleteAsync(string id)
    {
        var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));
        await _collection.DeleteOneAsync(filter);
    }

    public async Task<bool> ExistsAsync(string id)
    {
        var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));
        return await _collection.CountDocumentsAsync(filter) > 0;
    }
}

3.3 注册Repository服务

// 在Program.cs中添加
builder.Services.AddScoped<IRepository<Product>>(serviceProvider =>
{
    var database = serviceProvider.GetRequiredService<IMongoDatabase>();
    var settings = serviceProvider.GetRequiredService<IOptions<MongoDBSettings>>().Value;
    return new MongoRepository<Product>(database, settings.CollectionName);
});

四、控制器实现与API设计

4.1 Products控制器

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IRepository<Product> _productRepository;

    public ProductsController(IRepository<Product> productRepository)
    {
        _productRepository = productRepository;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
    {
        var products = await _productRepository.GetAllAsync();
        return Ok(products);
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<Product>> GetProduct(string id)
    {
        var product = await _productRepository.GetByIdAsync(id);
        if (product == null)
        {
            return NotFound();
        }
        return Ok(product);
    }

    [HttpPost]
    public async Task<ActionResult<Product>> CreateProduct(Product product)
    {
        await _productRepository.CreateAsync(product);
        return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product);
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateProduct(string id, Product product)
    {
        if (!await _productRepository.ExistsAsync(id))
        {
            return NotFound();
        }

        product.Id = id;
        await _productRepository.UpdateAsync(id, product);
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteProduct(string id)
    {
        if (!await _productRepository.ExistsAsync(id))
        {
            return NotFound();
        }

        await _productRepository.DeleteAsync(id);
        return NoContent();
    }
}

4.2 API端点功能表

HTTP方法端点功能描述状态码
GET/api/products获取所有产品200 OK
GET/api/products/{id}获取指定产品200 OK / 404 Not Found
POST/api/products创建新产品201 Created
PUT/api/products/{id}更新产品信息204 No Content / 404 Not Found
DELETE/api/products/{id}删除产品204 No Content / 404 Not Found

五、高级查询与聚合操作

5.1 扩展Repository支持复杂查询

public interface IProductRepository : IRepository<Product>
{
    Task<IEnumerable<Product>> GetByCategoryAsync(string category);
    Task<IEnumerable<Product>> SearchByNameAsync(string name);
    Task<IEnumerable<Product>> GetProductsInPriceRangeAsync(decimal minPrice, decimal maxPrice);
    Task<long> GetTotalCountAsync();
}

public class ProductRepository : MongoRepository<Product>, IProductRepository
{
    public ProductRepository(IMongoDatabase database, string collectionName) 
        : base(database, collectionName)
    {
    }

    public async Task<IEnumerable<Product>> GetByCategoryAsync(string category)
    {
        var filter = Builders<Product>.Filter.Eq(p => p.Category, category);
        return await _collection.Find(filter).ToListAsync();
    }

    public async Task<IEnumerable<Product>> SearchByNameAsync(string name)
    {
        var filter = Builders<Product>.Filter.Regex(p => p.Name, 
            new BsonRegularExpression(name, "i")); // 不区分大小写
        return await _collection.Find(filter).ToListAsync();
    }

    public async Task<IEnumerable<Product>> GetProductsInPriceRangeAsync(decimal minPrice, decimal maxPrice)
    {
        var filter = Builders<Product>.Filter.And(
            Builders<Product>.Filter.Gte(p => p.Price, minPrice),
            Builders<Product>.Filter.Lte(p => p.Price, maxPrice)
        );
        return await _collection.Find(filter).ToListAsync();
    }

    public async Task<long> GetTotalCountAsync()
    {
        return await _collection.CountDocumentsAsync(_ => true);
    }
}

5.2 聚合管道示例

public async Task<Dictionary<string, int>> GetProductCountByCategoryAsync()
{
    var pipeline = new BsonDocument[]
    {
        new BsonDocument("$group", 
            new BsonDocument
            {
                { "_id", "$category" },
                { "count", new BsonDocument("$sum", 1) }
            }
        ),
        new BsonDocument("$sort", new BsonDocument("count", -1))
    };

    var results = await _collection.Aggregate<BsonDocument>(pipeline).ToListAsync();
    
    return results.ToDictionary(
        x => x["_id"].AsString,
        x => x["count"].AsInt32
    );
}

六、性能优化策略

6.1 索引优化

// 在Repository构造函数中创建索引
public ProductRepository(IMongoDatabase database, string collectionName) 
    : base(database, collectionName)
{
    // 创建复合索引
    var indexKeys = Builders<Product>.IndexKeys
        .Ascending(p => p.Category)
        .Ascending(p => p.Price);
    
    var indexOptions = new CreateIndexOptions { Name = "Category_Price_Index" };
    var indexModel = new CreateIndexModel<Product>(indexKeys, indexOptions);
    
    _collection.Indexes.CreateOne(indexModel);
    
    // 创建文本搜索索引
    var textIndexKeys = Builders<Product>.IndexKeys.Text(p => p.Name);
    var textIndexModel = new CreateIndexModel<Product>(textIndexKeys);
    _collection.Indexes.CreateOne(textIndexModel);
}

6.2 查询性能优化表

优化策略实施方法性能提升效果
索引优化为常用查询字段创建索引查询速度提升10-100倍
投影优化只返回需要的字段减少网络传输和数据处理时间
分页查询使用Skip和Limit减少内存使用和响应时间
批量操作使用BulkWrite减少网络往返次数
连接池合理配置连接池大小提高并发处理能力

七、事务处理与数据一致性

7.1 多文档事务支持

public async Task<bool> TransferProductCategory(string productId, string newCategory)
{
    using var session = await _client.StartSessionAsync();
    session.StartTransaction();

    try
    {
        var product = await _collection.Find(session, p => p.Id == productId).FirstOrDefaultAsync();
        if (product == null)
            return false;

        product.Category = newCategory;
        product.UpdatedAt = DateTime.UtcNow;

        await _collection.ReplaceOneAsync(session, p => p.Id == productId, product);
        
        // 可以在这里添加其他相关操作
        await session.CommitTransactionAsync();
        return true;
    }
    catch
    {
        await session.AbortTransactionAsync();
        throw;
    }
}

7.2 数据一致性保障机制

mermaid

八、测试策略

8.1 单元测试示例

using Moq;
using Xunit;

public class ProductRepositoryTests
{
    private readonly Mock<IMongoCollection<Product>> _mockCollection;
    private readonly ProductRepository _repository;

    public ProductRepositoryTests()
    {
        _mockCollection = new Mock<IMongoCollection<Product>>();
        var mockDatabase = new Mock<IMongoDatabase>();
        mockDatabase.Setup(d => d.GetCollection<Product>("Products", null))
                   .Returns(_mockCollection.Object);
        
        _repository = new ProductRepository(mockDatabase.Object, "Products");
    }

    [Fact]
    public async Task CreateAsync_ShouldInsertProduct()
    {
        // Arrange
        var product = new Product { Name = "Test Product", Price = 100, Category = "Test" };
        
        // Act
        await _repository.CreateAsync(product);
        
        // Assert
        _mockCollection.Verify(c => c.InsertOneAsync(
            product, 
            null, 
            It.IsAny<CancellationToken>()), 
            Times.Once);
    }

    [Fact]
    public async Task GetByIdAsync_WithValidId_ReturnsProduct()
    {
        // Arrange
        var productId = ObjectId.GenerateNewId().ToString();
        var expectedProduct = new Product { Id = productId, Name = "Test Product" };
        
        var mockCursor = new Mock<IAsyncCursor<Product>>();
        mockCursor.SetupSequence(_ => _.MoveNextAsync(It.IsAny<CancellationToken>()))
                 .ReturnsAsync(true)
                 .ReturnsAsync(false);
        mockCursor.Setup(_ => _.Current).Returns(new[] { expectedProduct });
        
        _mockCollection.Setup(c => c.FindAsync(
            It.IsAny<FilterDefinition<Product>>(),
            It.IsAny<FindOptions<Product, Product>>(),
            It.IsAny<CancellationToken>()))
            .ReturnsAsync(mockCursor.Object);
        
        // Act
        var result = await _repository.GetByIdAsync(productId);
        
        // Assert
        Assert.NotNull(result);
        Assert.Equal(productId, result.Id);
    }
}

九、生产环境部署建议

9.1 连接字符串配置最佳实践

{
  "MongoDBSettings": {
    "ConnectionString": "mongodb://username:password@cluster0-shard-00-00.mongodb.net:27017,cluster0-shard-00-01.mongodb.net:27017,cluster0-shard-00-02.mongodb.net:27017/myDatabase?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true&w=majority",
    "DatabaseName": "production_db",
    "CollectionName": "products"
  }
}

【免费下载链接】aspnetcore dotnet/aspnetcore: 是一个 ASP.NET Core 应用程序开发框架的官方 GitHub 仓库,它包含了 ASP.NET Core 的核心源代码和技术文档。适合用于 ASP.NET Core 应用程序开发,特别是对于那些需要深入了解 ASP.NET Core 框架实现和技术的场景。特点是 ASP.NET Core 官方仓库、核心源代码、技术文档。 【免费下载链接】aspnetcore 项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值