19. 【.NET 8 实战--孢子记账--从单体到微服务】--记账模块--收支记录

server/2024/12/15 11:49:27/

在本篇文章中,我们将一起编写孢子记账的收支记录功能(CURD),同样我们只列出一个具体功能的实现,剩下的功能由读者实现。

一、 需求

需求如下:

编号需求说明
1新增记录1.记录内容包括转换前金额、转换后金额、分类、日期、所属账本、币种、备注; 2.如果选择的币种不是设置的主币种,则将金额转换为主币种的金额
2删除记录1.不存在的记录给予提示
3修改记录1. 不存在的记录给予提示;2. 如果选择的币种不是设置的主币种,则将金额转换为主币种的金额
4查询记录1. 支持查询某一个记录;2. 支持根据开始时间和结束时间分页查询

就目前来说这个需求比较简单,一共5个接口,都是简单的CURD操作。并且根据需求我们也分析出来了收支记录表 IncomeExpenditureRecord 的主要结构:转换前金额 BeforAmount 、转换后金额 AfterAmount 、收支分类 IncomeExpenditureClassificationId 、记录日期 RecordDate、所属账本 AccountBookId、记录币种 CurrencyId、备注 Remark 。其中收支分类、所属账本以及记录币种都是外键,备注可以为空。同时这里要注意的是与金额相关的字段都要用decimal类型来作为字段类型。

二、功能编写

2.1 数据库映射类编写

根据前面的分析,我们的数据库映射类如下:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using SporeAccounting.BaseModels;namespace SporeAccounting.Models;/// <summary>
/// 收支记录表
/// </summary>
[Table("IncomeExpenditureRecord")]
public class IncomeExpenditureRecord : BaseModel
{/// <summary>/// 转换前金额/// </summary>[Column(TypeName = "decimal(18,2)")][Required]public decimal BeforAmount { get; set; }/// <summary>/// 转换后金额/// </summary>[Column(TypeName = "decimal(18,2)")][Required]public decimal AfterAmount { get; set; }/// <summary>/// 收支分类Id/// </summary>[Column(TypeName = "nvarchar(36)")][ForeignKey("FK_IncomeExpenditureRecord_IncomeExpenditureClassification")][Required]public string IncomeExpenditureClassificationId { get; set; }/// <summary>/// 记录日期/// </summary>[Column(TypeName = "datetime")][Required]public DateTime RecordDate { get; set; } = DateTime.Now;/// <summary>/// 账簿Id/// </summary>[Column(TypeName = "nvarchar(36)")][ForeignKey("FK_IncomeExpenditureRecord_AccountBook")][Required]public string AccountBookId { get; set; }/// <summary>/// 转换前币种Id/// </summary>[Column(TypeName = "nvarchar(36)")][ForeignKey("FK_IncomeExpenditureRecord_Currency")][Required]public string CurrencyId { get; set; }/// <summary>/// 备注/// </summary>[Column(TypeName = "nvarchar(100)")]public string? Remark { get; set; }/// <summary>/// 用户id/// </summary>[Column(TypeName = "nvarchar(36)")][ForeignKey("FK_IncomeExpenditureRecord_SysUser")][Required]public string UserId { get; set; }/// <summary>/// 导航属性/// </summary>public SysUser User { get; set; }/// <summary>/// 导航属性/// </summary>public Currency Currency { get; set; }/// <summary>/// 导航属性/// </summary>public IncomeExpenditureClassification IncomeExpenditureClassification { get; set; }/// <summary>/// 导航属性/// </summary>public AccountBook AccountBook { get; set; }
}

关于外键指向的类的导航属性的增加这里就不展示了,请各位读者自己根据前面文章所讲的内容,以及专栏《轻松学EntityFramework Core》中关于导航属性的内容,自己手动编写相关代码。

2.2 实现需求

这一小节我们一起编写新增收支记录的功能,其他功能大家自己独立编写,然后对比我的代码。由于收支记录服务接口及其实现类和前面其他功能的类大致一样,因此这里我也就不再展示代码了,只展示新增收支记录Action的代码。

using System.Net;
using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SporeAccounting.BaseModels;
using SporeAccounting.BaseModels.ViewModel.Response;
using SporeAccounting.Models;
using SporeAccounting.Models.ViewModels;
using SporeAccounting.Server.Interface;namespace SporeAccounting.Controllers
{/// <summary>/// 收支记录控制器/// </summary>[Route("api/[controller]")][ApiController]public class IncomeExpenditureRecordController : BaseController{/// <summary>/// 收支记录服务/// </summary>private readonly IIncomeExpenditureRecordServer _incomeExpenditureRecordServer;/// <summary>/// 配置服务/// </summary>private readonly IConfigServer _configServer;/// <summary>/// 汇率记录服务/// </summary>private readonly IExchangeRateRecordServer _exchangeRateRecordServer;/// <summary>/// 币种服务/// </summary>private readonly ICurrencyServer _currencyServer;/// <summary>/// 映射器/// </summary>private readonly IMapper _mapper;/// <summary>/// 构造函数/// </summary>/// <param name="incomeExpenditureRecordServer"></param>/// <param name="configServer"></param>/// <param name="exchangeRateRecordServer"></param>/// <param name="currencyServer"></param>/// <param name="mapper"></param>public IncomeExpenditureRecordController(IIncomeExpenditureRecordServer incomeExpenditureRecordServer,IConfigServer configServer,IExchangeRateRecordServer exchangeRateRecordServer,ICurrencyServer currencyServer,IMapper mapper){_incomeExpenditureRecordServer = incomeExpenditureRecordServer;_configServer = configServer;_exchangeRateRecordServer = exchangeRateRecordServer;_currencyServer = currencyServer;_mapper = mapper;}/// <summary>/// 添加收支记录/// </summary>/// <param name="incomeExpenditureRecordAddViewModel"></param>/// <returns></returns>[HttpPost][Route("Add")]public ActionResult<ResponseData<bool>> Add([FromBody] IncomeExpenditureRecordAddViewModel incomeExpenditureRecordAddViewModel){try{string userId = GetUserId();//获取用户设置的主币种Config? config = _configServer.Query(userId, ConfigTypeEnum.Currency);if (config == null){return Ok(new ResponseData<bool>(HttpStatusCode.NotFound, "未设置主币种"));}// 如果选择的币种不是设置的主币种,则将金额转换为主币种的金额if (config.Value != incomeExpenditureRecordAddViewModel.CurrencyId){//查询主币种Currency? mainCurrency = _currencyServer.Query(config.Value);if (mainCurrency == null){return Ok(new ResponseData<bool>(HttpStatusCode.NotFound, "币种不存在"));}// 查询传入的币种Currency? recordCurrency = _currencyServer.Query(incomeExpenditureRecordAddViewModel.CurrencyId);if (recordCurrency == null){return Ok(new ResponseData<bool>(HttpStatusCode.NotFound, "币种不存在"));}//获取记录币种和主币种的汇率ExchangeRateRecord? exchangeRateRecord =_exchangeRateRecordServer.Query($"{mainCurrency.Abbreviation}_{recordCurrency.Abbreviation}");if (exchangeRateRecord == null){return Ok(new ResponseData<bool>(HttpStatusCode.NotFound, "汇率不存在"));}incomeExpenditureRecordAddViewModel.AfterAmount *= exchangeRateRecord.ExchangeRate;}IncomeExpenditureRecord incomeExpenditureRecord =_mapper.Map<IncomeExpenditureRecord>(incomeExpenditureRecordAddViewModel);incomeExpenditureRecord.UserId = userId;incomeExpenditureRecord.CreateDateTime = DateTime.Now;incomeExpenditureRecord.CreateUserId = userId;_incomeExpenditureRecordServer.Add(incomeExpenditureRecord);return Ok(new ResponseData<bool>(HttpStatusCode.OK, data: true));}catch (Exception e){return Ok(new ResponseData<bool>(HttpStatusCode.InternalServerError, "服务端异常"));}}}
}

这段代码定义了一个控制器 IncomeExpenditureRecordController,用于管理与收支记录相关的操作。控制器依赖多个服务接口来完成其逻辑,包括收支记录服务、配置服务、汇率记录服务、币种服务和映射器。
在控制器的 Add 方法中,首先从请求体中接收 IncomeExpenditureRecordAddViewModel 类型的对象。接着,通过 GetUserId 方法获取当前用户的ID,用于后续的用户绑定。
然后,系统会检查用户是否设置了主币种配置,如果没有,则返回“未设置主币种”的响应。如果输入的币种与用户设置的主币种不同,系统会通过 _currencyServer 查询主币种和输入的币种信息。如果任一币种不存在,则返回“币种不存在”的响应。
如果币种存在,则通过 _exchangeRateRecordServer 查询这两个币种的汇率信息。如果找不到汇率记录,则返回“汇率不存在”的响应。若汇率存在,则将输入的金额根据汇率转换为主币种金额。
在所有数据准备完成后,使用 _mapper 将视图模型 IncomeExpenditureRecordAddViewModel 转换为 IncomeExpenditureRecord 实体对象,并设置与用户相关的属性(如 UserIdCreateUserId)。最终,通过 _incomeExpenditureRecordServer 将新记录保存到数据库,并返回操作成功的响应。 如果在过程中发生异常,则返回“服务端异常”的响应。

三、总结

这篇文章我们一起实现了收支记录中的新增记录功能,这功能比前面咱们实现的功能稍显复杂,需要获取主币种、获取主币种与用户选择的币种之间的汇率,最后根据汇率换算成主币种。
下一篇文章我们将结合主币种设置以及收支记录实现切换主币种后重新计算以前记录的转换后的金额。


http://www.ppmy.cn/server/150340.html

相关文章

redis 怎么样删除list

在 Redis 中&#xff0c;可以使用以下方法删除列表或列表中的元素&#xff1a; 1. 删除整个列表 使用 DEL 命令删除一个列表键&#xff1a; DEL mylist这个命令会删除键 mylist 及其值&#xff08;无论 mylist 是一个列表还是其他类型的键&#xff09;。 2. 删除列表中的部分…

【人工智能-中级】卷积神经网络(CNN)的中阶应用:从图像分类到目标检测

文章目录 卷积神经网络(CNN)的中阶应用:从图像分类到目标检测1. 图像分类:CNN的基础应用CNN结构概述经典网络架构2. 目标检测:从分类到定位基于区域的目标检测方法单阶段目标检测方法边界框回归与NMS(Non-Maximum Suppression)3. 深度学习中的目标检测挑战与解决方案4. …

基于 webRTC Vue 的局域网 文件传输工具

文件传输工具&#xff0c;匿名加密&#xff0c;只需访问网页&#xff0c;即可连接到其他设备&#xff0c;基于 webRTC 和 Vue.js coturn TURN 服务器 docker pull coturn/coturn docker run -d --networkhost \-v $(pwd)/my.conf:/etc/coturn/turnserver.conf \coturn/coturn…

Linux常用指令-----下

Linux常用指令------上 Linux常用指令------中 Linux系列 文章目录 Linux系列前言一、more指令二、less指令三、head指令和tail指令四、grep指令五、zip指令和unzip指令六、tar指令1、打包压缩2. 预览3. 解压解包 前言 在上一篇博客中&#xff0c;我給大家介绍了cat指令&#…

Rust格式化输出用法汇总

文章目录 基本的格式化输出格式化占位符Format 特性总结 Rust的格式化输出是通过std::fmt模块提供的强大功能来实现的。Rust提供了灵活且功能强大的格式化字符串语法&#xff0c;允许开发者根据需求输出不同类型的数据。 基本的格式化输出 Rust中最常用的格式化输出方法是使用…

PDFMathTranslate,PDF多语言翻译,批量处理,学术论文,双语对照(WIN/MAC)

分享一个非常实用的PDF文档翻译项目——PDFMathTranslate。作为一个经常逛GitHub的开发者&#xff0c;我总喜欢翻看各种项目附带的论文&#xff0c;虽然大多时候是瞎研究&#xff0c;但却乐在其中。该项目能够完美保留公式、图表、目录和注释&#xff0c;对于需要阅读外文文献的…

科研绘图系列:R语言绘制网络图和密度分布图(network density plot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载图1图2图3图4图5图6图7图8系统信息参考介绍 R语言绘制网络图和密度分布图(network & density plot) 加载R包 library(magrittr) library(dplyr) library(…

【Linux】VFS虚拟文件系统介绍

在Linux中&#xff0c;Virtual Filesystem (VFS)&#xff0c;即虚拟文件系统&#xff0c;是一个重要的抽象层&#xff0c;用于统一管理各种不同类型的文件系统&#xff0c;使得用户和应用程序可以以一致的方式访问各种存储介质中的文件和目录。VFS位于系统调用接口和实际文件系…