一、技术栈后端ASP.NET Core 8 WebAPI数据库SQL ServerORMEntity Framework Core架构三层控制器→服务→仓储二、项目目录结构plaintextWMS.WebAPI // 接口层 控制器 WMS.Service // 业务逻辑层 WMS.Repository // 数据访问层 WMS.Entity // 实体、DTO、模型三、第一步数据库表直接执行 SQL1. 物料表sqlCREATE TABLE Material( Id INT IDENTITY(1,1) PRIMARY KEY, MaterialCode NVARCHAR(50) NOT NULL, MaterialName NVARCHAR(100) NOT NULL, Spec NVARCHAR(100), Unit NVARCHAR(20) );2. 仓库库位表sqlCREATE TABLE WarehouseLocation( Id INT IDENTITY(1,1) PRIMARY KEY, LocCode NVARCHAR(50) NOT NULL, LocName NVARCHAR(100), WarehouseCode NVARCHAR(50) );3. 库存表sqlCREATE TABLE Inventory( Id INT IDENTITY(1,1) PRIMARY KEY, MaterialCode NVARCHAR(50), LocCode NVARCHAR(50), BatchNo NVARCHAR(50), Qty DECIMAL(18,2) DEFAULT 0 );4. 入库单表sqlCREATE TABLE InStockOrder( Id INT IDENTITY(1,1) PRIMARY KEY, OrderNo NVARCHAR(50) NOT NULL, MaterialCode NVARCHAR(50), LocCode NVARCHAR(50), BatchNo NVARCHAR(50), InQty DECIMAL(18,2), CreateTime DATETIME DEFAULT GETDATE() );四、第二步实体类 EntityMaterial.cscsharp运行namespace WMS.Entity { public class Material { public int Id { get; set; } public string MaterialCode { get; set; } string.Empty; public string MaterialName { get; set; } string.Empty; public string? Spec { get; set; } public string? Unit { get; set; } } }Inventory.cscsharp运行namespace WMS.Entity { public class Inventory { public int Id { get; set; } public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal Qty { get; set; } } }InStockOrder.cscsharp运行namespace WMS.Entity { public class InStockOrder { public int Id { get; set; } public string OrderNo { get; set; } string.Empty; public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal InQty { get; set; } public DateTime CreateTime { get; set; } } }五、第三步DTO 入参模型csharp运行namespace WMS.Entity { public class InStockDto { public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal InQty { get; set; } } }六、第四步EF 数据库上下文csharp运行using Microsoft.EntityFrameworkCore; using WMS.Entity; namespace WMS.Repository { public class WmsDbContext : DbContext { public WmsDbContext(DbContextOptionsWmsDbContext options) : base(options) { } public DbSetMaterial Material { get; set; } public DbSetWarehouseLocation WarehouseLocation { get; set; } public DbSetInventory Inventory { get; set; } public DbSetInStockOrder InStockOrder { get; set; } } }七、第五步入库 接口控制器可直接用csharp运行using Microsoft.AspNetCore.Mvc; using WMS.Entity; using WMS.Repository; using Microsoft.EntityFrameworkCore; namespace WMS.WebAPI.Controllers { [ApiController] [Route(api/[controller])] public class InStockController : ControllerBase { private readonly WmsDbContext _db; public InStockController(WmsDbContext db) { _db db; } // 提交入库、自动加库存 [HttpPost(Create)] public async TaskIActionResult Create([FromBody] InStockDto dto) { // 1. 生成入库单号 string orderNo RK DateTime.Now.ToString(yyyyMMddHHmmss); // 2. 新增入库单 var order new InStockOrder { OrderNo orderNo, MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, InQty dto.InQty, CreateTime DateTime.Now }; _db.InStockOrder.Add(order); // 3. 更新库存有则累加无则新增 var inv await _db.Inventory .FirstOrDefaultAsync(x x.MaterialCode dto.MaterialCode x.LocCode dto.LocCode x.BatchNo dto.BatchNo); if (inv null) { _db.Inventory.Add(new Inventory { MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, Qty dto.InQty }); } else { inv.Qty dto.InQty; } await _db.SaveChangesAsync(); return Ok(new { Code 200, Msg 入库成功, OrderNo orderNo }); } } }八、第六步Program.cs 配置csharp运行var builder WebApplication.CreateBuilder(args); // 注册控制器 builder.Services.AddControllers(); // 注册EF SQL Server builder.Services.AddDbContextWmsDbContext(opt { opt.UseSqlServer(builder.Configuration.GetConnectionString(WmsConn)); }); var app builder.Build(); app.MapControllers(); app.Run();九、appsettings.json 连接字符串jsonConnectionStrings: { WmsConn: Server.;DatabaseWMSDB;Trusted_ConnectionTrue;TrustServerCertificateTrue }直接能用的功能物料、库位、库存、入库单 基础表齐全调用/api/InStock/Create即可完成入库 自动加库存标准 WebAPI 接口可给 PDA、前端、ERP 直接对接基于上面 WMS 项目直接复制就能用不用改架构。一、先补 2 张必备数据表执行 SQL出库单表sqlCREATE TABLE OutStockOrder( Id INT IDENTITY(1,1) PRIMARY KEY, OrderNo NVARCHAR(50) NOT NULL, MaterialCode NVARCHAR(50), LocCode NVARCHAR(50), BatchNo NVARCHAR(50), OutQty DECIMAL(18,2), CreateTime DATETIME DEFAULT GETDATE() );仓库库位表sqlCREATE TABLE WarehouseLocation( Id INT IDENTITY(1,1) PRIMARY KEY, LocCode NVARCHAR(50) NOT NULL, LocName NVARCHAR(100), WarehouseCode NVARCHAR(50) );二、新增实体类OutStockOrder.cscsharp运行namespace WMS.Entity { public class OutStockOrder { public int Id { get; set; } public string OrderNo { get; set; } string.Empty; public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal OutQty { get; set; } public DateTime CreateTime { get; set; } } }WarehouseLocation.cscsharp运行namespace WMS.Entity { public class WarehouseLocation { public int Id { get; set; } public string LocCode { get; set; } string.Empty; public string LocName { get; set; } string.Empty; public string WarehouseCode { get; set; } string.Empty; } }三、新增 DTO出库入参 DTOcsharp运行namespace WMS.Entity { public class OutStockDto { public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal OutQty { get; set; } } }库存分页查询 DTOcsharp运行namespace WMS.Entity { public class InventoryQueryDto { public string? MaterialCode { get; set; } public string? LocCode { get; set; } public int PageIndex { get; set; } 1; public int PageSize { get; set; } 10; } }四、新增 出库控制器 OutStockController自动校验库存是否充足 → 生成出库单 → 扣减库存csharp运行using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using WMS.Entity; using WMS.Repository; namespace WMS.WebAPI.Controllers { [ApiController] [Route(api/[controller])] public class OutStockController : ControllerBase { private readonly WmsDbContext _db; public OutStockController(WmsDbContext db) { _db db; } [HttpPost(Create)] public async TaskIActionResult Create([FromBody] OutStockDto dto) { // 1. 查当前库存 var inv await _db.Inventory .FirstOrDefaultAsync(x x.MaterialCode dto.MaterialCode x.LocCode dto.LocCode x.BatchNo dto.BatchNo); if (inv null || inv.Qty dto.OutQty) { return Ok(new { Code 500, Msg 库存不足无法出库 }); } // 2. 生成出库单号 string orderNo CK DateTime.Now.ToString(yyyyMMddHHmmss); // 3. 新增出库单 var outOrder new OutStockOrder { OrderNo orderNo, MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, OutQty dto.OutQty, CreateTime DateTime.Now }; _db.OutStockOrder.Add(outOrder); // 4. 扣减库存 inv.Qty - dto.OutQty; // 库存为0可选择删除该行这里保留记录 await _db.SaveChangesAsync(); return Ok(new { Code 200, Msg 出库成功, OrderNo orderNo }); } } }五、库存分页查询接口 InventoryController支持按物料编码、库位模糊查询 分页csharp运行using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using WMS.Entity; using WMS.Repository; namespace WMS.WebAPI.Controllers { [ApiController] [Route(api/[controller])] public class InventoryController : ControllerBase { private readonly WmsDbContext _db; public InventoryController(WmsDbContext db) { _db db; } [HttpPost(PageList)] public async TaskIActionResult PageList([FromBody] InventoryQueryDto dto) { var query _db.Inventory.AsQueryable(); // 条件过滤 if (!string.IsNullOrEmpty(dto.MaterialCode)) { query query.Where(x x.MaterialCode.Contains(dto.MaterialCode)); } if (!string.IsNullOrEmpty(dto.LocCode)) { query query.Where(x x.LocCode.Contains(dto.LocCode)); } // 分页 var total await query.CountAsync(); var list await query .Skip((dto.PageIndex - 1) * dto.PageSize) .Take(dto.PageSize) .ToListAsync(); return Ok(new { Code 200, Total total, List list }); } } }六、更新数据库上下文 WmsDbContext补上新增 DbSetcsharp运行public DbSetOutStockOrder OutStockOrder { get; set; } public DbSetWarehouseLocation WarehouseLocation { get; set; }七、现在整套 WMS 具备能力物料、库位、库存、入库单、出库单 完整表结构入库接口生成单据 自动加库存出库接口库存校验 生成单据 自动扣库存库存分页查询条件筛选、分页返回标准 WebAPI可对接PDA、Vue 前端、ERP、WCS下一步我可以再给你盘点接口盘点差异调整库存移库接口从 A 库位转到 B 库位金蝶 ERP 对接调用示例代码整套项目分层完整版接口层、服务层、仓储层拆分一、先执行全套数据库 SQL一次建完所有表sql-- 物料表 CREATE TABLE Material( Id INT IDENTITY(1,1) PRIMARY KEY, MaterialCode NVARCHAR(50) NOT NULL, MaterialName NVARCHAR(100) NOT NULL, Spec NVARCHAR(100), Unit NVARCHAR(20) ); -- 仓库库位表 CREATE TABLE WarehouseLocation( Id INT IDENTITY(1,1) PRIMARY KEY, LocCode NVARCHAR(50) NOT NULL, LocName NVARCHAR(100), WarehouseCode NVARCHAR(50) ); -- 库存表 CREATE TABLE Inventory( Id INT IDENTITY(1,1) PRIMARY KEY, MaterialCode NVARCHAR(50), LocCode NVARCHAR(50), BatchNo NVARCHAR(50), Qty DECIMAL(18,2) DEFAULT 0 ); -- 入库单表 CREATE TABLE InStockOrder( Id INT IDENTITY(1,1) PRIMARY KEY, OrderNo NVARCHAR(50) NOT NULL, MaterialCode NVARCHAR(50), LocCode NVARCHAR(50), BatchNo NVARCHAR(50), InQty DECIMAL(18,2), CreateTime DATETIME DEFAULT GETDATE() ); -- 出库单表 CREATE TABLE OutStockOrder( Id INT IDENTITY(1,1) PRIMARY KEY, OrderNo NVARCHAR(50) NOT NULL, MaterialCode NVARCHAR(50), LocCode NVARCHAR(50), BatchNo NVARCHAR(50), OutQty DECIMAL(18,2), CreateTime DATETIME DEFAULT GETDATE() ); -- 盘点单表 CREATE TABLE StockCheck( Id INT IDENTITY(1,1) PRIMARY KEY, CheckNo NVARCHAR(50), MaterialCode NVARCHAR(50), LocCode NVARCHAR(50), BatchNo NVARCHAR(50), SystemQty DECIMAL(18,2), CheckQty DECIMAL(18,2), DiffQty DECIMAL(18,2), CreateTime DATETIME DEFAULT GETDATE() ); -- 移库单表 CREATE TABLE MoveStock( Id INT IDENTITY(1,1) PRIMARY KEY, MoveNo NVARCHAR(50), MaterialCode NVARCHAR(50), BatchNo NVARCHAR(50), FromLoc NVARCHAR(50), ToLoc NVARCHAR(50), MoveQty DECIMAL(18,2), CreateTime DATETIME DEFAULT GETDATE() );二、完整实体类 Entity全部复制1. Material.cscsharp运行public class Material { public int Id { get; set; } public string MaterialCode { get; set; } string.Empty; public string MaterialName { get; set; } string.Empty; public string? Spec { get; set; } public string? Unit { get; set; } }2. WarehouseLocation.cscsharp运行public class WarehouseLocation { public int Id { get; set; } public string LocCode { get; set; } string.Empty; public string LocName { get; set; } string.Empty; public string WarehouseCode { get; set; } string.Empty; }3. Inventory.cscsharp运行public class Inventory { public int Id { get; set; } public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal Qty { get; set; } }4. InStockOrder.cscsharp运行public class InStockOrder { public int Id { get; set; } public string OrderNo { get; set; } string.Empty; public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal InQty { get; set; } public DateTime CreateTime { get; set; } }5. OutStockOrder.cscsharp运行public class OutStockOrder { public int Id { get; set; } public string OrderNo { get; set; } string.Empty; public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal OutQty { get; set; } public DateTime CreateTime { get; set; } }6. StockCheck.cscsharp运行public class StockCheck { public int Id { get; set; } public string CheckNo { get; set; } string.Empty; public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal SystemQty { get; set; } public decimal CheckQty { get; set; } public decimal DiffQty { get; set; } public DateTime CreateTime { get; set; } }7. MoveStock.cscsharp运行public class MoveStock { public int Id { get; set; } public string MoveNo { get; set; } string.Empty; public string MaterialCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public string FromLoc { get; set; } string.Empty; public string ToLoc { get; set; } string.Empty; public decimal MoveQty { get; set; } public DateTime CreateTime { get; set; } }三、DTO 模型全部复制1. InStockDto.cscsharp运行public class InStockDto { public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal InQty { get; set; } }2. OutStockDto.cscsharp运行public class OutStockDto { public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal OutQty { get; set; } }3. InventoryQueryDto.cscsharp运行public class InventoryQueryDto { public string? MaterialCode { get; set; } public string? LocCode { get; set; } public int PageIndex { get; set; } 1; public int PageSize { get; set; } 10; }4. StockCheckDto.cscsharp运行public class StockCheckDto { public string MaterialCode { get; set; } string.Empty; public string LocCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public decimal CheckQty { get; set; } }5. MoveStockDto.cscsharp运行public class MoveStockDto { public string MaterialCode { get; set; } string.Empty; public string BatchNo { get; set; } string.Empty; public string FromLoc { get; set; } string.Empty; public string ToLoc { get; set; } string.Empty; public decimal MoveQty { get; set; } }四、数据库上下文 WmsDbContext.cscsharp运行using Microsoft.EntityFrameworkCore; public class WmsDbContext : DbContext { public WmsDbContext(DbContextOptionsWmsDbContext options) : base(options) { } public DbSetMaterial Material { get; set; } public DbSetWarehouseLocation WarehouseLocation { get; set; } public DbSetInventory Inventory { get; set; } public DbSetInStockOrder InStockOrder { get; set; } public DbSetOutStockOrder OutStockOrder { get; set; } public DbSetStockCheck StockCheck { get; set; } public DbSetMoveStock MoveStock { get; set; } }五、全套控制器7 大核心接口直接复制1. 入库控制器 InStockControllercsharp运行[ApiController] [Route(api/[controller])] public class InStockController : ControllerBase { private readonly WmsDbContext _db; public InStockController(WmsDbContext db) _db db; [HttpPost(Create)] public async TaskIActionResult Create(InStockDto dto) { string orderNo RK DateTime.Now.ToString(yyyyMMddHHmmss); _db.InStockOrder.Add(new InStockOrder { OrderNo orderNo, MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, InQty dto.InQty, CreateTime DateTime.Now }); var inv await _db.Inventory.FirstOrDefaultAsync(x x.MaterialCode dto.MaterialCode x.LocCode dto.LocCode x.BatchNo dto.BatchNo); if (inv null) _db.Inventory.Add(new Inventory { MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, Qty dto.InQty }); else inv.Qty dto.InQty; await _db.SaveChangesAsync(); return Ok(new { Code 200, Msg 入库成功, OrderNo orderNo }); } }2. 出库控制器 OutStockControllercsharp运行[ApiController] [Route(api/[controller])] public class OutStockController : ControllerBase { private readonly WmsDbContext _db; public OutStockController(WmsDbContext db) _db db; [HttpPost(Create)] public async TaskIActionResult Create(OutStockDto dto) { var inv await _db.Inventory.FirstOrDefaultAsync(x x.MaterialCode dto.MaterialCode x.LocCode dto.LocCode x.BatchNo dto.BatchNo); if (inv null || inv.Qty dto.OutQty) return Ok(new { Code 500, Msg 库存不足 }); string orderNo CK DateTime.Now.ToString(yyyyMMddHHmmss); _db.OutStockOrder.Add(new OutStockOrder { OrderNo orderNo, MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, OutQty dto.OutQty, CreateTime DateTime.Now }); inv.Qty - dto.OutQty; await _db.SaveChangesAsync(); return Ok(new { Code 200, Msg 出库成功, OrderNo orderNo }); } }3. 库存查询 InventoryControllercsharp运行[ApiController] [Route(api/[controller])] public class InventoryController : ControllerBase { private readonly WmsDbContext _db; public InventoryController(WmsDbContext db) _db db; [HttpPost(PageList)] public async TaskIActionResult PageList(InventoryQueryDto dto) { var query _db.Inventory.AsQueryable(); if (!string.IsNullOrEmpty(dto.MaterialCode)) query query.Where(x x.MaterialCode.Contains(dto.MaterialCode)); if (!string.IsNullOrEmpty(dto.LocCode)) query query.Where(x x.LocCode.Contains(dto.LocCode)); var total await query.CountAsync(); var list await query.Skip((dto.PageIndex - 1) * dto.PageSize).Take(dto.PageSize).ToListAsync(); return Ok(new { Code 200, Total total, List list }); } }4. 盘点控制器 StockCheckControllercsharp运行[ApiController] [Route(api/[controller])] public class StockCheckController : ControllerBase { private readonly WmsDbContext _db; public StockCheckController(WmsDbContext db) _db db; [HttpPost(Create)] public async TaskIActionResult Create(StockCheckDto dto) { var inv await _db.Inventory.FirstOrDefaultAsync(x x.MaterialCode dto.MaterialCode x.LocCode dto.LocCode x.BatchNo dto.BatchNo); decimal sysQty inv?.Qty ?? 0; decimal diff dto.CheckQty - sysQty; var check new StockCheck { CheckNo PD DateTime.Now.ToString(yyyyMMddHHmmss), MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, SystemQty sysQty, CheckQty dto.CheckQty, DiffQty diff, CreateTime DateTime.Now }; _db.StockCheck.Add(check); if (inv ! null) inv.Qty dto.CheckQty; else _db.Inventory.Add(new Inventory { MaterialCode dto.MaterialCode, LocCode dto.LocCode, BatchNo dto.BatchNo, Qty dto.CheckQty }); await _db.SaveChangesAsync(); return Ok(new { Code 200, Msg 盘点完成 }); } }5. 移库控制器 MoveStockControllercsharp运行[ApiController] [Route(api/[controller])] public class MoveStockController : ControllerBase { private readonly WmsDbContext _db; public MoveStockController(WmsDbContext db) _db db; [HttpPost(Create)] public async TaskIActionResult Create(MoveStockDto dto) { var fromInv await _db.Inventory.FirstOrDefaultAsync(x x.MaterialCode dto.MaterialCode x.LocCode dto.FromLoc x.BatchNo dto.BatchNo); if (fromInv null || fromInv.Qty dto.MoveQty) return Ok(new { Code 500, Msg 源库位库存不足 }); string moveNo YK DateTime.Now.ToString(yyyyMMddHHmmss); _db.MoveStock.Add(new MoveStock { MoveNo moveNo, MaterialCode dto.MaterialCode, BatchNo dto.BatchNo, FromLoc dto.FromLoc, ToLoc dto.ToLoc, MoveQty dto.MoveQty, CreateTime DateTime.Now }); fromInv.Qty - dto.MoveQty; var toInv await _db.Inventory.FirstOrDefaultAsync(x x.MaterialCode dto.MaterialCode x.LocCode dto.ToLoc x.BatchNo dto.BatchNo); if (toInv null) _db.Inventory.Add(new Inventory { MaterialCode dto.MaterialCode, LocCode dto.ToLoc, BatchNo dto.BatchNo, Qty dto.MoveQty }); else toInv.Qty dto.MoveQty; await _db.SaveChangesAsync(); return Ok(new { Code 200, Msg 移库成功, MoveNo moveNo }); } }6. 物料控制器 MaterialControllercsharp运行[ApiController] [Route(api/[controller])] public class MaterialController : ControllerBase { private readonly WmsDbContext _db; public MaterialController(WmsDbContext db) _db db; [HttpGet(List)] public async TaskIActionResult List() Ok(await _db.Material.ToListAsync()); [HttpPost(Add)] public async TaskIActionResult Add(Material model) { _db.Material.Add(model); await _db.SaveChangesAsync(); return Ok(添加成功); } }7. ERP 对接通用接口给金蝶 / 用友 / SAPcsharp运行[ApiController] [Route(api/[controller])] public class ErpController : ControllerBase { [HttpPost(SyncInStock)] public IActionResult SyncInStock(object data) { // 在这里写对接ERP逻辑 return Ok(new { Code 200, Msg ERP同步成功 }); } [HttpPost(SyncOutStock)] public IActionResult SyncOutStock(object data) { return Ok(new { Code 200, Msg ERP同步成功 }); } }六、Program.cs 完整配置csharp运行var builder WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddDbContextWmsDbContext(opt opt.UseSqlServer(builder.Configuration.GetConnectionString(WmsConn))); var app builder.Build(); app.MapControllers(); app.Run();七、appsettings.json 连接字符串json{ ConnectionStrings: { WmsConn: Server.;DatabaseWMSDB;Trusted_ConnectionTrue;TrustServerCertificateTrue } }这套代码你现在拥有的功能✅ 入库 自动增加库存✅ 出库 库存校验 扣减库存✅ 库存查询 分页 筛选✅ 盘点单 自动调整库存✅ 移库单 库位库存转移✅ 物料管理✅ ERP 对接接口金蝶 / 用友 / SAP✅ 标准 WebAPI可给 PDA / 前端 / 上位机调用