使用c#oracle19c和sqlsugar实现erp单据新增时单据编号自增

文章目录

在ERP系统中,单据编号(如: RK202601190001 )的自动生成是常见的需求,格式为: [RK][日期][序号] ,其中:

  • RK:代表入库单据的标识(如流水号前缀)
  • 20260119:代表单据的生成日期
  • 0001:标识当天生成的第一张单据

实现步骤一:创建表

创建一个 SC_BILL_SEQ_LOG 表用于存储单据编号,如下:

建表 sql 语句如下:

sql 复制代码
-- Create table
create table C##RY_NET.SC_BILL_SEQ_LOG
(
  id            NUMBER(20) generated always as identity,
  billtype      VARCHAR2(50),
  datekey       DATE,
  currentnumber NUMBER default 1
)
tablespace USERS
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
-- Add comments to the table 
comment on table C##RY_NET.SC_BILL_SEQ_LOG
  is '单据序列日志表';
-- Add comments to the columns 
comment on column C##RY_NET.SC_BILL_SEQ_LOG.id
  is '自增ID';
comment on column C##RY_NET.SC_BILL_SEQ_LOG.billtype
  is '单据类型';
comment on column C##RY_NET.SC_BILL_SEQ_LOG.datekey
  is '日期';
comment on column C##RY_NET.SC_BILL_SEQ_LOG.currentnumber
  is '当前序号';
-- Create/Recreate primary, unique and foreign key constraints 
alter table C##RY_NET.SC_BILL_SEQ_LOG
  add constraint SC_BILL_SEQ_LOG_ID primary key (ID)
  using index
  tablespace USERS
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );

实现步骤二:实体类和Dto

实体类如下:

csharp 复制代码
using RuoYi.Data.Entities;
using SqlSugar;

namespace RuoYi.StockControll.Data.Entities
{
    /// <summary>
    ///  单据序列日志 对象 SC_BILL_SEQ_LOG
    ///  author cgs
    ///  date   2026-01-19 09:36:58
    /// </summary>
    [SugarTable("C##RY_NET.SC_BILL_SEQ_LOG", "单据序列日志表")]
    public class ScBillSeqLog : BaseEntity
    {
        /// <summary>
        /// 自增ID (ID)
        /// </summary>
        [SugarColumn(ColumnName = "ID", ColumnDescription = "自增ID", IsPrimaryKey = true, IsIdentity = true)]
        public int? Id { get; set; }

        /// <summary>
        /// 单据类型 (BILLTYPE)
        /// </summary>
        [SugarColumn(ColumnName = "BILLTYPE", ColumnDescription = "单据类型")]
        public string? Billtype { get; set; }

        /// <summary>
        /// 日期 (DATEKEY)
        /// </summary>
        [SugarColumn(ColumnName = "DATEKEY", ColumnDescription = "日期")]
        public DateTime? Datekey { get; set; }

        /// <summary>
        /// 当前序号 (CURRENTNUMBER)
        /// </summary>
        [SugarColumn(ColumnName = "CURRENTNUMBER", ColumnDescription = "当前序号")]
        public int? Currentnumber { get; set; }
    }
}

DTO 如下:

csharp 复制代码
using RuoYi.Data.Dtos;

namespace RuoYi.StockControll.Data.Dtos
{
    /// <summary>
    ///  单据序列日志 对象 SC_BILL_SEQ_LOG
    ///  author cgs
    ///  date   2026-01-19 09:36:58
    /// </summary>
    public class ScBillSeqLogDto : BaseDto
    {
        /// <summary>
        /// 自增ID
        /// </summary>
        public int? Id { get; set; }

        /// <summary>
        /// 单据类型
        /// </summary>
        public string? Billtype { get; set; }

        /// <summary>
        /// 日期
        /// </summary>
        public DateTime? Datekey { get; set; }

        /// <summary>
        /// 当前序号
        /// </summary>
        public int? Currentnumber { get; set; }
    }
}

实现步骤三:仓储层

仓储层如下:

csharp 复制代码
using RuoYi.Common.Data;
using RuoYi.StockControll.Data.Dtos;
using RuoYi.StockControll.Data.Entities;
using SqlSugar;

namespace RuoYi.StockControll.Repositories
{
    /// <summary>
    ///  单据序列日志 Repository
    ///  author cgs
    ///  date   2026-01-19 09:36:58
    /// </summary>
    public class ScBillSeqLogRepository : BaseRepository<ScBillSeqLog, ScBillSeqLogDto>
    {
        public ScBillSeqLogRepository(ISqlSugarRepository<ScBillSeqLog> sqlSugarRepository)
        {
            Repo = sqlSugarRepository;
        }

        public override ISugarQueryable<ScBillSeqLog> Queryable(ScBillSeqLogDto dto)
        {
            return Repo.AsQueryable()
                .WhereIF(dto.Id != null && dto.Id > 0, (t) => t.Id == dto.Id)
                .WhereIF(!string.IsNullOrEmpty(dto.Billtype), (t) => t.Billtype == dto.Billtype!)
                .WhereIF(dto.Datekey != null, (t) => t.Datekey == dto.Datekey)
                .WhereIF(dto.Currentnumber != null, (t) => t.Currentnumber == dto.Currentnumber)
            ;
        }

        public override ISugarQueryable<ScBillSeqLogDto> DtoQueryable(ScBillSeqLogDto dto)
        {
            return Repo.AsQueryable()
                .WhereIF(dto.Id != null && dto.Id > 0, (t) => t.Id == dto.Id)
                .WhereIF(!string.IsNullOrEmpty(dto.Billtype), (t) => t.Billtype == dto.Billtype!)
                .WhereIF(dto.Datekey != null, (t) => t.Datekey == dto.Datekey)
                .WhereIF(dto.Currentnumber != null, (t) => t.Currentnumber == dto.Currentnumber)
                .Select((t) => new ScBillSeqLogDto
                {
                    Id = t.Id
                }, true);
        }
    }
}

其中 BaseRepositoryruoyi.net 的后端,代码不贴了,参考:https://gitee.com/wdyday/RuoYi.Net

实现步骤四:服务层

服务层如下:

csharp 复制代码
using Mapster;
using Microsoft.Extensions.Logging;
using RuoYi.Common.Data;
using RuoYi.Framework.DependencyInjection;
using RuoYi.StockControll.Data.Dtos;
using RuoYi.StockControll.Data.Entities;
using RuoYi.StockControll.Interfaces;
using RuoYi.StockControll.Repositories;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace RuoYi.StockControll.Services
{
    /// <summary>
    ///  单据序列日志 Service
    ///  author cgs
    ///  date   2026-01-19 09:36:58
    /// </summary>
    public class ScBillSeqLogService : BaseService<ScBillSeqLog, ScBillSeqLogDto>, ITransient, IGenBillNumService
    {
        private readonly ILogger<ScBillSeqLogService> _logger;
        private readonly ScBillSeqLogRepository _scBillSeqLogRepository;

        public ScBillSeqLogService(ILogger<ScBillSeqLogService> logger,
            ScBillSeqLogRepository scBillSeqLogRepository)
        {
            BaseRepo = scBillSeqLogRepository;

            _logger = logger;
            _scBillSeqLogRepository = scBillSeqLogRepository;
        }

        /// <summary>
        /// 查询 单据序列日志 详情
        /// </summary>
        public async Task<ScBillSeqLog> GetAsync(string id)
        {
            var entity = await base.FirstOrDefaultAsync(e => e.Billtype == id);
            return entity;
        }

        /// <summary>
        /// 查询 单据序列日志 详情
        /// </summary>
        public async Task<ScBillSeqLogDto> GetDtoAsync(string id)
        {
            var entity = await base.FirstOrDefaultAsync(e => e.Billtype == id);
            var dto = entity.Adapt<ScBillSeqLogDto>();
            // TODO 填充关联表数据
            return dto;
        }

        /// <inheritdoc/>
        public async Task<string> GenerateBillNumberAsync(string billType = "RK")
        {
            var date = DateTime.Now.Date;
            var billSeqLogDto = await this._scBillSeqLogRepository.GetDtoFirstAsync(new ScBillSeqLogDto
            {
                Billtype = billType,
                Datekey = date
            });

            if (billSeqLogDto == null)
            {
                ////this._scBillSeqLogRepository.Insert(new ScBillSeqLog
                ////{
                ////    Billtype = billType,
                ////    Datekey = date,
                ////    Currentnumber = 1
                ////});

                return $"{billType}{date.ToString("yyyyMMdd")}0001";
            }

            return $"{billType}{date.ToString("yyyyMMdd")}{(billSeqLogDto!.Currentnumber + 1):D4}";
        }

        /// <inheritdoc/>
        public async Task<string> SaveBillNumberAsync(string billType)
        {
            try
            {
                var date = DateTime.Now.Date;
                int newNumber = 1;
                await this.BaseRepo.Repo.Context.AsTenant().BeginTranAsync();
                var billSeqLogDto = await this._scBillSeqLogRepository.GetDtoFirstAsync(new ScBillSeqLogDto
                {
                    Billtype = billType,
                    Datekey = date
                });

                if (billSeqLogDto != null)
                {
                    newNumber = (billSeqLogDto!.Currentnumber ?? 0) + 1;
                    int ret = await this._scBillSeqLogRepository.UpdateAsync(new ScBillSeqLog
                    {
                        Id = billSeqLogDto.Id,
                        Billtype = billType,
                        Datekey = date,
                        Currentnumber = newNumber
                    });
                }
                else
                {
                    bool ret = await this._scBillSeqLogRepository.InsertAsync(new ScBillSeqLog
                    {
                        Billtype = billType,
                        Datekey = date,
                        Currentnumber = newNumber
                    });
                }

                await this.BaseRepo.Repo.Context.AsTenant().CommitTranAsync();
                return $"{billType}{date.ToString("yyyyMMdd")}{newNumber:D4}";
            }
            catch (Exception)
            {
                this.BaseRepo.Repo.Context.AsTenant().RollbackTran();
                throw;
            }
        }
    }
}

实现步骤五:控制器

控制器如下:

csharp 复制代码
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using RuoYi.Framework;
using RuoYi.StockControll.Services;

namespace RuoYi.StockControll.Controllers
{
    /// <summary>
    /// 单据序列日志
    /// </summary>
    [ApiDescriptionSettings("sc")]
    [Route("sc/billseqlog")]
    public class ScBillSeqLogController : ControllerBase
    {
        private readonly ILogger<ScBillSeqLogController> _logger;
        private readonly ScBillSeqLogService _scBillSeqLogService;

        public ScBillSeqLogController(ILogger<ScBillSeqLogController> logger,
            ScBillSeqLogService scBillSeqLogService)
        {
            _logger = logger;
            _scBillSeqLogService = scBillSeqLogService;
        }

        /// <summary>
        /// 生成单据编号.
        /// </summary>
        [HttpGet("genbillnum")]
        public async Task<AjaxResult> GenBillNum([FromQuery]string billType)
        {
            if (string.IsNullOrEmpty(billType) || (billType != "RK" && billType != "CK"))
            {
                return AjaxResult.Error("参数不正确");
            }

            var billNum = await _scBillSeqLogService.GenerateBillNumberAsync(billType);
            return AjaxResult.Success("操作成功", billNum);
        }

        /// <summary>
        /// 查询单据序列日志列表
        /// </summary>
        [HttpGet("savebillnum")]
        public async Task<AjaxResult> SaveBillNum([FromQuery]string billType)
        {
            if (string.IsNullOrEmpty(billType) || (billType != "RK" && billType != "CK"))
            {
                return AjaxResult.Error("参数不正确");
            }

            var billNum = await _scBillSeqLogService.SaveBillNumberAsync(billType);
            return AjaxResult.Success("操作成功", billNum);
        }
    }
}
相关推荐
游乐码2 小时前
c#里氏替换
开发语言·c#
未来之窗软件服务2 小时前
AI人工智能(十二)C# 运行sensevoice onnx—东方仙盟练气期
开发语言·人工智能·c#·仙盟创梦ide·东方仙盟
bugcome_com2 小时前
深入理解 C# 结构体(Struct):原理、对比与最佳实践
c#
游乐码2 小时前
c#继承中的构造函数
开发语言·c#
观无9 小时前
VisionPro颜色ROI识别+距离测量
c#
工程师00720 小时前
MQTT 概念详解与 C# 实战
开发语言·c#·mqtt通信
bugcome_com1 天前
C# 字符串(String)详解与常用操作示例
c#
游乐码1 天前
c#运算符重载
开发语言·c#