手记

使用ASP.NET Core和PostgreSQL构建简单的增删改查API接口

在这份指南中,我们将介绍如何构建一个 CRUD API 使用 ASP.NET CoreEntity Framework Core (EF Core)PostgreSQL。应用程序将遵循 整洁架构原则 ,将代码组织到仓库层和服务层中。这种结构促进了不同职责的分离,使代码库更加易维护和测试。这种结构使代码更清晰,更容易维护和测试。

1. 项目搭建

创建一个新的ASP.NET Core Web API

我们将从创建一个新的ASP.NET Core Web API项目开始,这将成为我们应用的基础。

  1. 打开终端(或命令行提示符)。
  2. 运行以下命令以创建项目如下:
mkdir PostgresCrud  # 创建一个名为PostgresCrud的目录
cd PostgresCrud      # 进入该目录
dotnet new webapi -n PostgresCrud  # 使用dotnet创建一个新的webapi项目,命名为PostgresCrud

进入全屏,退出全屏

  • dotnet new webapi 创建一个新的默认配置的 Web API 项目。
  • cd PostgresCrud 切换到 PostgresCrud 文件夹。

现在,我们有一个叫 PostgresCrud 的 ASP.NET Core Web API 项目。

2. 设置 PostgreSQL

appsettings.json文件中配置连接字符串

PostgreSQL的连接串将存储在appsettings.json文件中。该文件包含了应用程序所需的配置,比如数据库连接信息。

示例配置appsettings.json:

    {
      "ConnectionStrings": {
        "DefaultConnection": "Host=localhost;Database=webapi_demo;Username=postgres;Password=mysecretpassword"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }

切换到全屏模式 退出全屏

  • Host=localhost : PostgreSQL 数据库是在本地主机上运行。
  • Database=webapi_demo : 数据库名称为。
  • Username=postgres : PostgreSQL 用户名是。
  • Password=mysecretpassword : PostgreSQL 密码是。
3. 安装依赖项.

在我们开始与PostgreSQL数据库互动之前,我们需要先安装必要的NuGet包。

添加 Microsoft.EntityFrameworkCore 包 - 用于 Entity Framework Core  
添加 Npgsql.EntityFrameworkCore.PostgreSQL 包 - 用于 PostgreSQL 数据库的 Entity Framework Core  
添加 Swashbuckle.AspNetCore 包 - 用于生成 API 文档的 Swagger 工具 

进入全屏 退出全屏

  • Microsoft.EntityFrameworkCore :添加 Entity Framework Core (EF Core) ORM 以处理数据库操作。
  • Npgsql.EntityFrameworkCore.PostgreSQL :为 PostgreSQL 数据库提供支持。
  • Swashbuckle.AspNetCore :添加 Swagger 以生成 API 文档并进行测试。
4. 数据库上下文(ApplicationDbContext.cs)

ApplicationDbContext 是什么?

ApplicationDbContext 类起到连接我们应用程序和 PostgreSQL 数据库的桥梁作用。它包含表示数据库中表的 DbSet 属性,这些属性对应于数据库中的表。

文件名:Data/ApplicationDbContext.cs

    using Microsoft.EntityFrameworkCore;
    using PostgresCrud.Entities;

    命名空间 PostgresCrud.Data
    {
        公共类 public ApplicationDbContext : DbContext
        {
            public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) 
                : base(options) { }

            public DbSet<Product> Products { get; set; }
        }
    }

进入全屏 退出全屏

  • DbContext : EF Core 提供的用于数据库操作的基础类,或者说,一个数据库操作的基类。
  • DbSet<Product> Products:它代表 PostgreSQL 中的 Products 表,每个 DbSet 对象都对应数据库中的一张表。
5. 定义实体对象:(Product.cs)

你知道什么是实体吗?

实体定义了数据库表的结构。在这种情况下,Product 实体代表存储在 Products 表中的产品。

文件:Entities/Product.cs

    命名空间 PostgresCrud.Entities
    {
        public class Product
        {
            public int Id { get; set; }
            public string Name { get; set; } = string.Empty;
            public decimal Price { get; set; }
        }
    }

切换到全屏 退出全屏

  • Id :这是产品的唯一标识符。
  • Name :产品的名称。
  • Price :产品的售价。

实现仓储模式

仓库模式(Repository Pattern)帮助我们将数据库操作封装在一个单独的类里,从而使代码更整洁和有条理。仓库将通过EF Core与数据库交互。

定义仓库的接口

文件路径:仓储层/IProductRepository.cs

using PostgresCrud.Entities;

namespace PostgresCrud.Repositories
{
    public interface IProductRepository
    {
        Task<IEnumerable<Product>> GetAllAsync(); // 获取所有产品的异步方法
        Task<Product> GetByIdAsync(int id); // 根据ID获取产品的异步方法
        Task AddAsync(Product product); // 添加产品的异步方法
        Task UpdateAsync(Product product); // 更新产品的异步方法
        Task DeleteAsync(int id); // 根据ID删除产品的异步方法
    }
}

进入全屏 退出全屏

IProductRepository接口定义了五个增删改查(CRUD)操作
——

  • GetAllAsync(): 获取所有产品。
  • GetByIdAsync(int id):根据ID获取产品。
  • AddAsync(Product product):添加新商品。
  • UpdateAsync(Product product):更新现有商品。
  • DeleteAsync(int id):根据ID删除商品。

实现仓库模式

文件:Repositories/ProductRepository.cs

    using Microsoft.EntityFrameworkCore; // 导入 Entity Framework Core 用于数据库相关操作
    using PostgresCrud.Data; // 导入应用程序数据库上下文
    using PostgresCrud.Entities; // 导入 Product 实体

    namespace PostgresCrud.Repositories
    {
        public class ProductRepository : IProductRepository
        {
            private readonly ApplicationDbContext _context; // 数据库上下文用于与数据库交互

            public ProductRepository(ApplicationDbContext context)
            {
                _context = context; // 通过构造函数注入数据库上下文对象
            }

            // 获取所有产品
            public async Task<IEnumerable<Product>> GetAllAsync()
            {
                // 将 Products 表转换为列表并异步返回
                return await _context.Products.ToListAsync();
            }

            // 通过 ID 获取产品
            public async Task<Product> GetByIdAsync(int id)
            {
                // 使用 FindAsync 根据主键(ID)查找产品
                return await _context.Products.FindAsync(id);
            }

            // 添加新产品到数据库
            public async Task AddAsync(Product product)
            {
                // 将产品添加到数据库上下文中
                await _context.Products.AddAsync(product);

                // 异步保存更改到数据库
                await _context.SaveChangesAsync();
            }

            // 更新现有产品
            public async Task UpdateAsync(Product product)
            {
                // 在数据库上下文中标记产品已更新
                _context.Products.Update(product);
            }

            // 删除指定 ID 的产品
            public async Task DeleteAsync(int id)
            {
                // 使用提供的 ID 在数据库中查找产品
                var product = await _context.Products.FindAsync(id);

                // 如果找到产品,则将其删除
                if (product != null)
                {
                    _context.Products.Remove(product);

                    // 异步保存更改到数据库
                    await _context.SaveChangesAsync();
                }
            }
        }
    }

点击全屏 点击退出全屏

  • ProductRepository 类实现了 IProductRepository 接口定义的 CRUD 方法。它通过 ApplicationDbContext 与数据库进行直接交互。
第七章 实现服务层实现

在ASP.NET Core应用程序中,服务层充当控制器(API层)和仓储(数据访问层)之间的桥梁。不仅包含业务逻辑,还确保数据在传递给API请求者之前进行恰当的处理。

定义服务接口

文件名:Services/IProductService.cs

    using PostgresCrud.DTOs;

    namespace PostgresCrud.Services
    {
        public interface IProductService
        {
            Task<IEnumerable<ProductResponseDto>> 异步获取所有产品();
            Task<ProductResponseDto> 异步通过Id获取产品(int id);
            Task 异步添加产品(ProductRequestDto productDto);
            Task 异步更新产品(int id, ProductRequestDto productDto);
            Task 异步删除产品(int id);
        }
    }

全屏 退出全屏

该服务接口包括以下方法。

  • 从仓库中取出产品。
  • 实体模型 转换为 DTO 以便传输数据。

服务的实施

文件:Services/ProductService.cs,如下所示:

    using PostgresCrud.Entities; // 导入 Product 实体
    using PostgresCrud.DTOs; // 导入请求和响应的数据传输对象 (DTOs)
    using PostgresCrud.Repositories; // 导入用于数据访问的 Product 仓库

    namespace PostgresCrud.Services
    {
        public class ProductService : IProductService
        {
            private readonly IProductRepository _productRepository; // 用于数据库操作的仓库实例

            public ProductService(IProductRepository productRepository)
            {
                _productRepository = productRepository; // 通过构造函数注入仓库实例
            }

            // 获取所有产品,将其转换为 DTO 并返回列表
            public async Task<IEnumerable<ProductResponseDto>> GetAllProductsAsync()
            {
                var products = await _productRepository.GetAllAsync(); // 从仓库获取所有产品

                // 将每个产品实体转换为 ProductResponseDto 并返回
                return products.Select(p => new ProductResponseDto 
                { 
                    Id = p.Id, 
                    Name = p.Name, 
                    Price = p.Price 
                });
            }

            // 根据 ID 获取产品,并将其转换为 DTO
            public async Task<ProductResponseDto> GetProductByIdAsync(int id)
            {
                var product = await _productRepository.GetByIdAsync(id); // 根据 ID 获取产品

                // 如果未找到产品,则抛出异常
                if (product == null)
                    throw new KeyNotFoundException("产品未找到");

                // 将实体转换为 DTO 并返回
                return new ProductResponseDto 
                { 
                    Id = product.Id, 
                    Name = product.Name, 
                    Price = product.Price 
                };
            }

            // 使用请求 DTO 添加新产品
            public async Task AddProductAsync(ProductRequestDto productDto)
            {
                // 将 DTO 转换为实体
                var product = new Product
                {
                    Name = productDto.Name,
                    Price = productDto.Price
                };

                // 将新产品添加到数据库
                await _productRepository.AddAsync(product);
            }

            // 使用新数据更新现有产品
            public async Task UpdateProductAsync(int id, ProductRequestDto productDto)
            {
                var product = await _productRepository.GetByIdAsync(id); // 根据 ID 获取产品

                // 如果产品不存在,则抛出异常
                if (product == null)
                    throw new KeyNotFoundException("产品未找到");

                // 使用 DTO 中的新值更新产品字段
                product.Name = productDto.Name;
                product.Price = productDto.Price;

                // 将更新后的产品保存到数据库
                await _productRepository.UpdateAsync(product);
            }

            // 根据 ID 删除产品
            public async Task DeleteProductAsync(int id)
            {
                var product = await _productRepository.GetByIdAsync(id); // 根据 ID 获取产品

                // 如果产品不存在,则抛出异常
                if (product == null)
                    throw new KeyNotFoundException("产品未找到");

                // 从数据库中删除产品
                await _productRepository.DeleteAsync(id);
            }
        }
    }

全屏模式(点击退出)
双击退出

服务层将实体模型转换为DTO(数据传输对象),使数据更便于API消费者处理。它在调用仓库层之前处理所有必要的业务逻辑。

服务方法分类
方法 描述
GetAllProductsAsync 获取所有产品,将其转换为 DTO 并返回。
GetProductByIdAsync 根据 ID 获取单个产品。如果未找到,则抛出 KeyNotFoundException 异常。
AddProductAsync ProductRequestDto 转换为 Product 实体并将其保存到数据库。
UpdateProductAsync 检查产品是否存在,更新其字段并保存更改。如果产品不存在,则抛出 ProductNotFoundException 异常。
DeleteProductAsync 检查产品是否存在,如果存在则删除。如果未找到,则抛出 ProductNotFoundException 异常。
设置 API 控制器部分

创建产品控制

ProductController将负责定义API端点。

文件路径:Controllers/ProductController.cs

    using Microsoft.AspNetCore.Mvc; // 导入ASP.NET Core MVC框架
    using PostgresCrud.Services; // 导入服务层模块
    using PostgresCrud.DTOs; // 导入数据传输对象(DTOs)

    namespace PostgresCrud.Controllers
    {
        [ApiController] // 指定这是一个API控制器
        [Route("api/[controller]")] // 定义路由为'api/product'
        public class ProductController : ControllerBase
        {
            private readonly IProductService _productService; // 用于处理业务逻辑的服务实例

            public ProductController(IProductService productService)
            {
                _productService = productService; // 通过构造函数注入服务
            }

            // 异步获取所有产品
            [HttpGet]
            public async Task<IActionResult> GetAll()
            {
                var products = await _productService.GetAllProductsAsync(); // 获取所有产品
                return Ok(products); // 返回包含产品数据的200 OK响应
            }

            // 异步通过ID获取单个产品
            [HttpGet("{id}")]
            public async Task<IActionResult> GetById(int id)
            {
                try
                {
                    var product = await _productService.GetProductByIdAsync(id); // 获取指定产品
                    return Ok(product); // 如果找到产品,则返回200 OK响应;如果没有找到产品,则返回404 Not Found响应
                }
                catch (KeyNotFoundException)
                {
                    return NotFound(); // 如果产品不存在,则返回404 Not Found响应
                }
            }

            // 异步添加新产品
            [HttpPost]
            public async Task<IActionResult> Add(ProductRequestDto productDto)
            {
                await _productService.AddProductAsync(productDto); // 添加新产品
                return CreatedAtAction(nameof(GetById), new { id = productDto.Id }, productDto); 
                // 返回201 Created响应,并通过定位头指向新创建的产品
            }

            // 异步更新现有产品
            [HttpPut("{id}")]
            public async Task<IActionResult> Update(int id, ProductRequestDto productDto)
            {
                try
                {
                    await _productService.UpdateProductAsync(id, productDto); // 更新产品
                    return NoContent(); // 如果操作成功,则返回204 No Content响应
                }
                catch (KeyNotFoundException)
                {
                    return NotFound(); // 如果产品不存在,则返回404 Not Found响应
                }
            }

            // 异步删除产品
            [HttpDelete("{id}")]
            public async Task<IActionResult> Delete(int id)
            {
                try
                {
                    await _productService.DeleteProductAsync(id); // 删除指定的产品
                    return NoContent(); // 如果操作成功,则返回204 No Content响应
                }
                catch (KeyNotFoundException)
                {
                    return NotFound(); // 如果产品不存在,则返回404 Not Found响应
                }
            }
        }
    }

进入全屏 退出全屏

下面是一个解释 ProductController 中每个方法的表格:

方法 HTTP 动词 路由 描述
GetAll GET /api/product 获取所有产品并以 JSON 数组形式返回结果。
GetById GET /api/product/{id} 通过 ID 获取单个产品。如果产品不存在,则返回 404 Not Found
Add POST /api/product 接收一个 ProductRequestDto 来创建一个新的产品。
Update PUT /api/product/{id} 使用所提供的 ID 和 DTO 更新现有产品。
Delete DELETE /api/product/{id} 通过 ID 删除产品。删除成功时返回 204 No Content,如果产品不存在则返回 404 Not Found
9. 设置依赖注入

最后,将所有内容连接起来,在 Program.cs 文件里为依赖注入功能注册服务和存储库。

代码文件:Program.cs

    using Microsoft.EntityFrameworkCore;
    using PostgresCrud.Data;
    using PostgresCrud.Repositories;
    using PostgresCrud.Services;

    var builder = WebApplication.CreateBuilder(args);

    // 向容器中添加服务。
    builder.Services.AddControllers();

    // 配置 PostgreSQL 数据库连接
    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

    // 注册仓储与服务
    builder.Services.AddScoped<IProductRepository, ProductRepository>();
    builder.Services.AddScoped<IProductService, ProductService>();

    // 如需了解更多关于 Swagger/OpenAPI 配置的信息,请访问 https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();

    var app = builder.Build();

    // 配置 HTTP 请求管道如下。
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }

    app.UseHttpsRedirection();

    app.UseAuthorization();

    app.MapControllers();

    app.Run();

进入全屏 退出全屏

10. 运行应用程序

完成所有实施后,我们现在就可以跑这个应用了。

  1. 如有必要,应用任何数据库迁移:

运行以下命令来添加初始迁移并更新数据库:

dotnet ef migrations add InitialCreate
dotnet ef database update

全屏 全屏退出

  1. 打开应用
dotnet run (运行.NET程序)

进入全屏,退出全屏

通过 Swagger UI 访问 API,地址为 http://localhost:5052/swagger

第十一部分总结

通过这种结构,我们得到了:

  • 设置一个ASP.NET Core Web API项目。
  • 使用PostgreSQL和Entity Framework Core来处理数据库操作。
  • 按照清洁架构原则,将关注点分开,比如存储库、服务和控制器。
  • 实现了一个带有结构化错误处理功能和适当HTTP状态码的CRUD API

这种结构使得我们的应用程序在增长时更容易管理和测试,并且可以更方便地进行扩展。
[OOP]:面向对象编程(OOP)
[CRUD]:增删查改(CRUD操作)
[JVM]:Java虚拟机(JVM)
[SUT]:系统被测试(SUT)

0人推荐
随时随地看视频
慕课网APP