项目背景WMS 智能仓储管理系统:
1.实现简单的增删改查:
1.1. Entities:
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Qhbx.Tibet.Wms.Entities.Basic
{
/// <summary>
/// 货物信息
/// </summary>
[Table("bx_wms_goods")]
public class GoodsEntity : Entity
{
/// <summary>
/// 货物类别
/// </summary>
[Required]
[StringLength(32)]
[Description("货物类别")]
public string GcId { get; set; }
/// <summary>
/// 货物编号
/// </summary>
[Required]
[StringLength(32)]
[Description("货物编号"), UniqueIndexKey]
public string GoodsCode { get; set; }
/// <summary>
/// 货物名称
/// </summary>
[Required]
[StringLength(100)]
[Description("货物名称")]
public string GoodsName { get; set; }
/// <summary>
/// 内包装数量
/// </summary>
[Description("内包装数量")]
public double InnerPackingQuantity { get; set; }
/// <summary>
/// 内包装货物体积
/// </summary>
[Description("内包装货物体积")]
public double InnerPackingVolume { get; set; }
/// <summary>
/// 内包装货物重量
/// </summary>
[Description("内包装货物重量")]
public double InnerPackingWeight { get; set; }
/// <summary>
/// 材质
/// </summary>
[StringLength(32)]
[Description("材质")]
public string Material { get; set; }
/// <summary>
/// 最大库存量
/// </summary>
[Description("最大库存量")]
public double MaxStock { get; set; }
/// <summary>
/// 最小库存量
/// </summary>
[Description("最小库存量")]
public double MinStock { get; set; }
/// <summary>
/// 外包装数量
/// </summary>
[Description("外包装数量")]
public double OuterPackingQuantity { get; set; }
/// <summary>
/// 外包装货物重量
/// </summary>
[Description("外包装货物重量")]
public double OuterPackingWeight { get; set; }
/// <summary>
/// 价格
/// </summary>
[Description("价格")]
public double Price { get; set; }
/// <summary>
/// 重量
/// </summary>
[Description("重量")]
public double Weight { get; set; }
/// <summary>
/// 保质期
/// </summary>
[Description("保质期")]
public double ShelfLife { get; set; }
/// <summary>
/// 规格
/// </summary>
[Required]
[StringLength(50)]
[Description("规格")]
public string Specs { get; set; }
/// <summary>
/// 供应商编号
/// </summary>
[Required]
[StringLength(32)]
[Description("供应商编号")]
public string SupplierId { get; set; }
/// <summary>
/// 状态
/// </summary>
[Description("状态(0启用1禁用)")]
public override Status Status { get; set; }
/// <summary>
/// 是否删除(0未删除1已删除)
/// </summary>
[Description("是否删除(0未删除1已删除)")]
public override DeleteStatus IsDelete { get; set; }
/// <summary>
/// 创建人
/// </summary>
[StringLength(32)]
[Description("创建人")]
public override string Creator { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[Description("创建时间")]
public override DateTime CreateDate { get; set; }
/// <summary>
/// 编辑人
/// </summary>
[StringLength(32)]
[Description("编辑人")]
public override string Updator { get; set; }
/// <summary>
/// 编辑时间
/// </summary>
[Description("编辑时间")]
public override DateTime UpdateDate { get; set; }
}
}
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Qhbx.Tibet.Wms.Entities
{
/// <summary>
/// 实体类基类
/// </summary>
public abstract class Entity : IMapper
{
/// <summary>
/// 编号
/// </summary>
[Key]
[Required]
[StringLength(32)]
[Description("编号")]
public virtual string Id { get; set; }
/// <summary>
/// 状态
/// </summary>
public virtual Status Status { get; set; }
/// <summary>
/// 是否删除(0未删除1已删除)
/// </summary>
public virtual DeleteStatus IsDelete { get; set; }
/// <summary>
/// 创建人id
/// </summary>
[StringLength(32)]
public virtual string Creator { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public virtual DateTime CreateDate { get; set; }
/// <summary>
/// 编辑人id
/// </summary>
[StringLength(32)]
public virtual string Updator { get; set; }
/// <summary>
/// 编辑时间
/// </summary>
public virtual DateTime UpdateDate { get; set; }
}
}
1.2 Model:
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Qhbx.Tibet.Wms.Models.Basic
{
/// <summary>
/// 货物信息的模型
/// </summary>
public class GoodsModel: IMapper
{
/// <summary>
/// 编号
/// </summary>
[Key]
[MaxLength(32, ErrorMessage = "编号的最大长度是32")]
public virtual string Id { get; set; }
/// <summary>
/// 货物类别
/// </summary>
[Required]
[MaxLength(32, ErrorMessage = "货物类别的最大长度是32")]
public string GcId { get; set; }
/// <summary>
/// 货物类别名称
/// </summary>
public string GcName { get; set; }
/// <summary>
/// 货物编号
/// </summary>
[Required]
[MaxLength(32, ErrorMessage = "货物编号的最大长度是32")]
public string GoodsCode { get; set; }
/// <summary>
/// 货物名称
/// </summary>
[Required]
[MaxLength(100, ErrorMessage = "货物名称的最大长度是100")]
public string GoodsName { get; set; }
/// <summary>
/// 内包装数量
/// </summary>
public double InnerPackingQuantity { get; set; }
/// <summary>
/// 内包装货物体积
/// </summary>
public double InnerPackingVolume { get; set; }
/// <summary>
/// 内包装货物重量
/// </summary>
public double InnerPackingWeight { get; set; }
/// <summary>
/// 材质
/// </summary>
[MaxLength(32, ErrorMessage = "材质的最大长度是32")]
public string Material { get; set; }
/// <summary>
/// 最大库存量
/// </summary>
public double MaxStock { get; set; }
/// <summary>
/// 最小库存量
/// </summary>
public double MinStock { get; set; }
/// <summary>
/// 外包装数量
/// </summary>
public double OuterPackingQuantity { get; set; }
/// <summary>
/// 外包装货物重量
/// </summary>
public double OuterPackingWeight { get; set; }
/// <summary>
/// 价格
/// </summary>
public double Price { get; set; }
/// <summary>
/// 重量
/// </summary>
public double Weight { get; set; }
/// <summary>
/// 保质期
/// </summary>
public double ShelfLife { get; set; }
/// <summary>
/// 规格
/// </summary>
[Required]
[MaxLength(50, ErrorMessage = "规格的最大长度是50")]
public string Specs { get; set; }
/// <summary>
/// 供应商编号
/// </summary>
[Required]
[MaxLength(32)]
public string SupplierId { get; set; }
/// <summary>
/// 供应商名称
/// </summary>
public string SupplierName { get; set; }
/// <summary>
/// 状态(0启用,1禁用)
/// </summary>
[Range(0, 1, ErrorMessage = "{0}只能是0或者1【0启用,1禁用】")]
public Status Status { get; set; }
/// <summary>
/// 状态名称
/// </summary>
public string StatusText => this.Status.GetDescription();
/// <summary>
/// 是否删除(0未删除1已删除)
/// </summary>
[Range(0, 1, ErrorMessage = "{0}值只能是0或者1【0未删除,1已删除】")]
public DeleteStatus IsDelete { get; set; }
/// <summary>
/// 状态名称
/// </summary>
public string IsDeleteText => this.IsDelete.GetDescription();
/// <summary>
/// 创建人
/// </summary>
[MaxLength(32, ErrorMessage = "创建人的最大长度是32")]
public string Creator { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateDate { get; set; }
/// <summary>
/// 编辑人
/// </summary>
[MaxLength(32, ErrorMessage = "编辑人的最大长度是32")]
public string Updator { get; set; }
/// <summary>
/// 编辑时间
/// </summary>
public DateTime UpdateDate { get; set; }
}
}
1.3 API-Controllers
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Api.Filters;
using Qhbx.Tibet.Wms.Api.Models;
using Qhbx.Tibet.Wms.Core;
using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.IServices.Basic;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.Basic;
namespace Qhbx.Tibet.Wms.Api.Controllers
{
/// <summary>
/// 货物
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
[Authorize]
[FunctionAuthorize(FunctionConst.GoodsFuncCode)]
public class GoodsController : ControllerBase
{
private IGoodsService _service { get; }
private ILogger _log { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="service"></param>
/// <param name="logger"></param>
public GoodsController(IGoodsService service, ILogger<GoodsController> logger)
{
_service = service;
_log = logger;
}
/// <summary>
/// 获取货物列表分页数据
/// </summary>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页显示条数</param>
/// <param name="key">查询条件(货物编号、货物名称、货物类别、供应商编号)</param>
/// <returns></returns>
[HttpGet]
[Log("获取货物列表分页数据")]
public Page<GoodsModel> GetPageList(int pageIndex = 1, int pageSize = 10, string key = "")
{
return _service.GetPageList(pageIndex, pageSize, key);
}
/// <summary>
/// 获取货物列表数据
/// </summary>
/// <param name="key">查询条件(Name或Code或Id)</param>
/// <returns></returns>
[HttpGet]
[Log("获取货物列表数据")]
public async Task<List<GoodsModel>> GetList(string key = "")
{
return await _service.GetList(key);
}
/// <summary>
/// 添加货物信息
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
[Log("添加货物信息")]
public async Task<IActionResult> Add(GoodsModel model)
{
model.Id = GuidUtil.FormatN();
model.Creator = User.GetUserId();
model.CreateDate = System.DateTime.Now;
model.UpdateDate = System.DateTime.Now;
model.Updator = User.GetUserId();
await _service.AddAsync(model);
return Ok();
}
/// <summary>
/// 更新货物信息
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
[Log("更新货物信息")]
public async Task<IActionResult> Edit(GoodsModel model)
{
model.UpdateDate = System.DateTime.Now;
model.Updator = User.GetUserId();
await _service.EditAsync(model);
return Ok();
}
/// <summary>
/// 批量删除货物信息
/// </summary>
/// <param name="ids">主键ID</param>
/// <returns></returns>
[HttpDelete]
[Log("删除货物信息")]
public async Task<IActionResult> Delete(string[] ids)
{
var updator = User.GetUserId();
await _service.DeleteAsync(ids, updator);
return Ok();
}
}
}
1.4 IService
using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.Basic;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Qhbx.Tibet.Wms.IServices.Basic
{
/// <summary>
/// 货物的服务接口
/// </summary>
public interface IGoodsService : IService<GoodsEntity>
{
/// <summary>
/// 获取货物列表分页数据
/// </summary>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页显示条数</param>
/// <param name="key">查询条件货(物编号、货物名称、货物类别、供应商编号)</param>
/// <returns></returns>
Page<GoodsModel> GetPageList(int pageIndex = 1, int pageSize = 10, string key = "");
/// <summary>
/// 获取货物列表数据
/// </summary>
/// <param name="key">查询条件</param>
/// <returns></returns>
Task<List<GoodsModel>> GetList(string key = "");
/// <summary>
/// 添加货物信息
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task AddAsync(GoodsModel entity);
/// <summary>
/// 更新货物信息
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task EditAsync(GoodsModel entity);
/// <summary>
/// 批量删除货物信息
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task DeleteAsync(string[] ids,string updator);
}
}
1.5 Service
using Microsoft.EntityFrameworkCore;
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.IServices;
using Qhbx.Tibet.Wms.IServices.Basic;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.Basic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Qhbx.Tibet.Wms.Services.Basic
{
/// <summary>
/// 货物的服务基类
/// </summary>
public class GoodsService : IGoodsService
{
/// <summary>
/// 构造方法
/// </summary>
/// <param name="dbContext"></param>
public GoodsService(DbContext dbContext, AutoMapper.IMapper mapper)
{
Context = dbContext;
Mapper = mapper;
}
/// <summary>
/// 数据库上下文
/// </summary>
public DbContext Context { get; set; }
public AutoMapper.IMapper Mapper { get; set; }
/// <summary>
/// 添加货物信息
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task AddAsync(GoodsModel model)
{
if (await this.ContainsAsync(x => x.GoodsCode == model.GoodsCode && x.IsDelete == DeleteStatus.Normal))
{
throw new CustomException($"货物编号【{model.GoodsCode}】已存在");
}
if (await this.ContainsAsync(x => x.GoodsName == model.GoodsName.Trim() && x.IsDelete == DeleteStatus.Normal))
{
throw new CustomException($"货物名称【{model.GoodsName}】已存在");
}
var entity = Mapper.Map<GoodsEntity>(model);
await this.InsertAsync(entity);
}
/// <summary>
/// 修改货物信息
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task EditAsync(GoodsModel model)
{
if (await this.Context.Set<GoodsEntity>().CountAsync(x => x.Id == model.Id && x.IsDelete == DeleteStatus.Normal) > 0)
{
if (await this.ContainsAsync(x => x.GoodsCode == model.GoodsCode && x.Id != model.Id && x.IsDelete == DeleteStatus.Normal))
{
throw new CustomException($"货物编号【{model.GoodsCode}】已存在");
}
if (await this.ContainsAsync(x => x.GoodsName == model.GoodsName.Trim() && x.Id != model.Id && x.IsDelete == DeleteStatus.Normal))
{
throw new CustomException($"货物名称【{model.GoodsName}】已存在");
}
var entity = Mapper.Map<GoodsEntity>(model);
await this.UpdateAsync(entity);
}
else
{
throw new CustomException("该货物不存在!");
}
}
/// <summary>
/// 获取货物列表分页数据
/// </summary>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页显示条数</param>
/// <param name="key">查询条件(货物编号、货物名称、货物类别、供应商编号)</param>
/// <returns></returns>
public Page<GoodsModel> GetPageList(int pageIndex = 1, int pageSize = 10, string key = "")
{
Expression<Func<GoodsEntity, bool>> predicate = e => e.IsDelete == DeleteStatus.Normal;
if (!string.IsNullOrWhiteSpace(key))
predicate = predicate.And(x => x.GoodsCode.Contains(key) || x.GoodsName.Contains(key) || x.GcId.Contains(key) || x.SupplierId.Contains(key));
var goods = from good in this.Context.Set<GoodsEntity>().Where(predicate)
join supplier in this.Context.Set<SupplierEntity>() on good.SupplierId equals supplier.Id into suppliers
from supplierDefault in suppliers.DefaultIfEmpty()
join dic in this.Context.Set<DictionaryEntity>() on good.GcId equals dic.Id into dics
from dicDefault in dics.DefaultIfEmpty()
select new GoodsModel
{
Id = good.Id,
GcId = good.GcId,
GcName = dicDefault.Name,
GoodsCode = good.GoodsCode,
GoodsName = good.GoodsName,
InnerPackingQuantity = good.InnerPackingQuantity,
InnerPackingVolume = good.InnerPackingVolume,
InnerPackingWeight = good.InnerPackingWeight,
Material = good.Material,
MaxStock = good.MaxStock,
MinStock = good.MinStock,
OuterPackingQuantity = good.OuterPackingQuantity,
OuterPackingWeight = good.OuterPackingWeight,
Price = good.Price,
Weight = good.Weight,
ShelfLife = good.ShelfLife,
Specs = good.Specs,
SupplierId = good.SupplierId,
SupplierName = supplierDefault.SupplierName,
Status = good.Status,
IsDelete = good.IsDelete,
Creator = good.Creator,
CreateDate = good.CreateDate,
Updator = good.Updator,
UpdateDate = good.UpdateDate
};
if (pageIndex <= 0) pageIndex = 1;
if (pageSize <= 0) pageSize = 10;
IEnumerable<GoodsModel> datas = goods.OrderByDescending(g => g.UpdateDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
Page<GoodsModel> page = new Page<GoodsModel> { Index = pageIndex, Size = pageSize, Datas = datas, Amount = goods.Count() };
return page;
}
/// <summary>
/// 获取货物列表数据
/// </summary>
/// <param name="key">查询条件(Name或Code或Id)</param>
/// <returns></returns>
public async Task<List<GoodsModel>> GetList(string key = "")
{
Expression<Func<GoodsEntity, bool>> predicate = e => e.IsDelete == DeleteStatus.Normal;
if (!string.IsNullOrWhiteSpace(key))
{
predicate = predicate.And(e => e.GoodsName.Contains(key) || e.GoodsCode.Contains(key) || e.Id == key);
}
var result = await this.WhereAsync(predicate);
var list = Mapper.Map<List<GoodsModel>>(result);
return list;
}
/// <summary>
/// 批量删除货物信息
/// </summary>
/// <param name="models"></param>
/// <returns></returns>
public async Task DeleteAsync(string[] ids, string updator)
{
var goodss = await this.WhereAsync(a => ids.Contains(a.Id) && a.IsDelete == Core.EnumDefinitions.DeleteStatus.Normal);
if (goodss.Count() == 0)
{
throw new CustomException("货物信息已经被删除,或者不存在!");
}
goodss = goodss.Select(a => { a.IsDelete = Core.EnumDefinitions.DeleteStatus.HasDelete; a.UpdateDate = DateTime.Now; a.Updator = updator; return a; });
foreach (var goods in goodss)
{
await this.UpdateIncludeAsync(goods, a => new { a.IsDelete, a.UpdateDate, a.Updator });
}
}
}
}
1.6 更新该实例的指定属性 的方法
/// <summary>
/// 更新该实例的指定属性
/// </summary>
/// <typeparam name="Tproperty">属性类型</typeparam>
/// <typeparam name="TEntity">实例类型</typeparam>
/// <param name="sender"></param>
/// <param name="entity">要更新的实例</param>
/// <param name="propertys">要更新的属性</param>
/// <returns></returns>
public static async Task<int> UpdateIncludeAsync<Tproperty, TEntity>(this IService<TEntity> sender, TEntity entity, Expression<Func<TEntity, Tproperty>> propertys)
where TEntity : class
{
if (propertys == null) return default;
var entry = sender.Context.Entry<TEntity>(entity);
var propertyNames = propertys.GetPropertys();
foreach (var propName in propertyNames)
{
entry.Property(propName).IsModified = true;
}
return await sender.Context.SaveChangesAsync();
}
2.一次性获取 1:多(入库单:入库单明细)信息 集合 使用GroupJoin对主子表集合进行关联
2.1一次性获取 1:多(入库单:入库单明细)信息 [先查主表,然后对主表进行分页,再通过主表分页后的数据获取其入库单明细信息,最后使用GroupJoin对主子表集合进行关联]
Expression<Func<InStockDemandBillEntity, bool>> predicate = e => e.IsDelete == DeleteStatus.Normal;
if (!string.IsNullOrWhiteSpace(key))
predicate = predicate.And(x => x.DemandNo.Contains(key) || x.Id.Contains(key) || x.SupplierId.Contains(key));
if (inStatus >= 0)
predicate = predicate.And(x => x.InStockStatus == (InStockStatus)inStatus);//Enum的Equals不会转换为SQL语句
if (planStartDate != null)
predicate = predicate.And(x => x.PlanArrivalTime >= ConvertHelper.ConvertToDateTime((long)planStartDate));
if (planEndDate != null)
predicate = predicate.And(x => x.PlanArrivalTime <= ConvertHelper.ConvertToDateTime((long)planEndDate));
if (actualStartDate != null)
predicate = predicate.And(x => x.ActualArrivalTime >= ConvertHelper.ConvertToDateTime((long)actualStartDate));
if (actualEndDate != null)
predicate = predicate.And(x => x.ActualArrivalTime <= ConvertHelper.ConvertToDateTime((long)actualEndDate));
//入库单信息
var inStocks = from instock in this.Context.Set<InStockDemandBillEntity>().Where(predicate)
join supplier in this.Context.Set<SupplierEntity>() on instock.SupplierId equals supplier.Id into suppliers
from supplierDefault in suppliers.DefaultIfEmpty()
join area in this.Context.Set<WareHouseAreaEntity>() on instock.AreaId equals area.Id into areas
from areaDefault in areas.DefaultIfEmpty()
join dic in this.Context.Set<DictionaryEntity>() on instock.InstockGroup equals dic.Id into dics
from dicInstockGroup in dics.DefaultIfEmpty()
join dic_a in this.Context.Set<DictionaryEntity>() on instock.ActualInstockGroup equals dic_a.Id into dic_as
from dicActualInstockGroup in dic_as.DefaultIfEmpty()
join dic_i in this.Context.Set<DictionaryEntity>() on instock.InstockNature equals dic_i.Id into dic_is
from dicInstockNature in dic_is.DefaultIfEmpty()
select new InStockDemandBillModel
{
Id = instock.Id,
DemandNo = instock.DemandNo,
InstockGroup = instock.InstockGroup,
InstockGroupName = dicInstockGroup.Name,
OrderNo = instock.OrderNo,
PlanArrivalTime = instock.PlanArrivalTime,
ActualArrivalTime = instock.ActualArrivalTime,
ActualInstockGroup = instock.ActualInstockGroup,
ActualInstockGroupName = dicActualInstockGroup.Name,
DeliveryCompany = instock.DeliveryCompany,
DeliveryMan = instock.DeliveryMan,
Status = instock.Status,
InStockStatus = instock.InStockStatus,
SupplierId = instock.SupplierId,
SupplierName = supplierDefault.SupplierName,
VehicleNo = instock.VehicleNo,
InstockNature = instock.InstockNature,
InstockNatureName = dicInstockNature.Name,
GroundingGroup = instock.GroundingGroup,
AppointmentUser = instock.AppointmentUser,
AppointmentDate = instock.AppointmentDate,
CheckUser = instock.CheckUser,
CheckTime = instock.CheckTime,
TaskUser = instock.TaskUser,
TaskTime = instock.TaskTime,
AreaId = instock.AreaId,
AreaName = areaDefault.AreaName,
IsDelete = instock.IsDelete,
Creator = instock.Creator,
CreateDate = instock.CreateDate,
Updator = instock.Updator,
UpdateDate = instock.UpdateDate
};
if (pageIndex <= 0) pageIndex = 1;
if (pageSize <= 0) pageSize = 10;
IEnumerable<InStockDemandBillModel> datas = inStocks.OrderByDescending(g => g.UpdateDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
Page<InStockDemandBillModel> page = new Page<InStockDemandBillModel> { Index = pageIndex, Size = pageSize, Datas = datas.ToList(), Amount = inStocks.Count() };
//入库单明细信息
var inStockItems = from instockItem in this.Context.Set<InStockDemandBillItemEntity>()
join goods in this.Context.Set<GoodsEntity>() on instockItem.GoodsId equals goods.Id into goodses
from good in goodses.DefaultIfEmpty()
join unloadwayDic in this.Context.Set<DictionaryEntity>() on instockItem.UnloadWay equals unloadwayDic.Id into unloadways
from unloadway in unloadways.DefaultIfEmpty()
select new InStockDemandBillItemModel
{
Id = instockItem.Id,
InstockDemandBillId = instockItem.InstockDemandBillId,
PlanArrivalQuantity = instockItem.PlanArrivalQuantity,
ProductBatch = instockItem.ProductBatch,
ActualArrivalQuantity = instockItem.ActualArrivalQuantity,
ActualProductBatch = instockItem.ActualProductBatch,
GoodsId = instockItem.GoodsId,
GoodsName = good.GoodsName,
PackingSpecs = instockItem.PackingSpecs,
UnloadWay = instockItem.UnloadWay,
UnloadWayName = unloadway.Name,
IsDelete = instockItem.IsDelete,
Creator = instockItem.Creator,
CreateDate = instockItem.CreateDate,
Updator = instockItem.Updator,
UpdateDate = instockItem.UpdateDate
};
page.Datas = page.Datas.GroupJoin<InStockDemandBillModel, InStockDemandBillItemModel, string, InStockDemandBillModel>(
inStockItems, idb => idb.Id, isdbtm => isdbtm.InstockDemandBillId, (instock, instockbillitems) =>
{
InStockDemandBillModel inStockDemandBillModel = instock;
inStockDemandBillModel.InStockItems = instockbillitems;
return inStockDemandBillModel;
}
);
return page;
2.2 多表同时添加 采用事务处理
/// <summary>
/// 添加入库单
/// </summary>
/// <param name="inStockModel"></param>
/// <returns></returns>
public async Task AddAsync(InStockDemandBillModel inStockModel)
{
if (inStockModel.AppointmentDate.Date < DateTime.Now.Date)
{
throw new CustomException("预约日期不能小于当前日期");
}
if (inStockModel.PlanArrivalTime < System.DateTime.Now)
{
throw new CustomException("计划到货时间不能小于当前时间");
}
//入库单 数据添加
var inStockEntity = Mapper.Map<InStockDemandBillEntity>(inStockModel);
inStockEntity.Id = GuidUtil.FormatN();
inStockEntity.DemandNo = CommonConst.RK.CreateBillCode();
this.Context.Set<InStockDemandBillEntity>().Add(inStockEntity);
//入库明细 数据添加
foreach (var item in inStockModel.InStockItems)
{
var inStockItemEntity = Mapper.Map<InStockDemandBillItemEntity>(item);
inStockItemEntity.Id = GuidUtil.FormatN();
inStockItemEntity.InstockDemandBillId = inStockEntity.Id;
this.Context.Set<InStockDemandBillItemEntity>().Add(inStockItemEntity);
}
//事务处理
var tran = this.Context.Database.BeginTransaction();
try
{
await this.Context.SaveChangesAsync();
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
throw new CustomException($"添加入库单信息异常,异常信息:" + ex.Message);
}
}
3.其他代码段:
using Microsoft.EntityFrameworkCore;
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.Entities.OutStock;
using Qhbx.Tibet.Wms.Entities.Stock;
using Qhbx.Tibet.Wms.IServices;
using Qhbx.Tibet.Wms.IServices.OutStock;
using Qhbx.Tibet.Wms.IServices.Stock;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.OutStock;
using Qhbx.Tibet.Wms.Models.Stock;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Qhbx.Tibet.Wms.Services.OutStock
{
/// <summary>
/// 出库单接口实现类
/// </summary>
public class OutStockService : IOutStockService
{
public OutStockService(DbContext dbContext, AutoMapper.IMapper mapper,IStockService stockService)
{
Context = dbContext;
Mapper = mapper;
_stockService = stockService;
}
public DbContext Context { get; set; }
public AutoMapper.IMapper Mapper { get; set; }
public IStockService _stockService { get; set; }
/// <summary>
/// 新增预约出库单
/// </summary>
/// <param name="outmodel"></param>
/// <returns></returns>
public async Task AddAsync(OutstockDemandBillModel outmodel)
{
if (outmodel.AppointmentDate.Date < DateTime.Now.Date)
{
throw new CustomException("预约日期不能小于当前日期");
}
if (outmodel.PlanArrivalTime <= System.DateTime.Now)
{
throw new CustomException("计划出库时间应大于当前时间");
}
//对应业务数据处理
var outStockEntity = Mapper.Map<OutstockDemandBillEntity>(outmodel);
outStockEntity.Id = Guid.NewGuid().ToString("N");
outStockEntity.DemandNo = BillExtend.CreateBillCode(CommonConst.CK);
this.Context.Set<OutstockDemandBillEntity>().Add(outStockEntity);
//明细数据处理
foreach (var item in outmodel.Items)
{
var outStockItemEntity = Mapper.Map<OutstockDemandBillItemEntity>(item);
outStockItemEntity.Id = Guid.NewGuid().ToString("N");
outStockItemEntity.OutstockDemandBillId = outStockEntity.Id;
Context.Set<OutstockDemandBillItemEntity>().Add(outStockItemEntity);
}
//事物操作
var tran = Context.Database.BeginTransaction();
try
{
await Context.SaveChangesAsync();
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
throw new CustomException(ex.Message);
}
}
/// <summary>
/// 删除预约出库单
/// </summary>
/// <param name="outOrderIds">预约出库单Id集合</param>
/// <param name="userId">操作人</param>
/// <returns></returns>
public async Task DeleteAsync(IEnumerable<string> outOrderIds, string userId)
{
if (outOrderIds.Count() == 0)
{
throw new CustomException("请传入有效的出库单Id");
}
var outStockEntitys = this.Context.Set<OutstockDemandBillEntity>().Where(x => x.IsDelete == DeleteStatus.Normal && outOrderIds.Contains(x.Id)).ToList();
if (outStockEntitys.Count() == 0)
{
throw new CustomException("未找到可删除的记录,请检查参数是否传递正确。");
}
var noDeleteItems = outStockEntitys.Where(x => x.OutStatus != OutOderStatus.TodoAllot);
if (noDeleteItems.Count() > 0)
{
throw new CustomException($" { string.Join(",", noDeleteItems.Select(x => x.DemandNo))}当前状态不可删除");
}
await Context.SaveChangesAsync();
foreach (var item in outStockEntitys)
{
item.IsDelete = Core.EnumDefinitions.DeleteStatus.HasDelete;
item.Updator = userId;
item.UpdateDate = DateTime.Now;
await this.UpdateAsync(item);
}
}
/// <summary>
/// 编辑预约出库单
/// </summary>
/// <param name="outmodel">操作对象</param>
/// <param name="oprerType">操作类型(0编辑预约单 1预约单任务分配,2预约出库单下架)</param>
/// <returns></returns>
public async Task EditAsync(OutstockDemandBillModel outmodel, OutOrderOperType operatorType)
{
var outStockEntitys = this.Context.Set<OutstockDemandBillEntity>().SingleOrDefault(x => x.Id == outmodel.Id && x.IsDelete == DeleteStatus.Normal);
if (outStockEntitys == null)
{
throw new CustomException("请传入有效的出库单Id");
}
if (outmodel.AppointmentDate.Date > outmodel.PlanArrivalTime)
{
throw new CustomException("预约时间不能大于计划出库时间!");
}
Func<string, string> func = goodsId =>
{
return this.Context.Set<GoodsEntity>().FirstOrDefault(x => x.IsDelete == DeleteStatus.Normal && x.Id == goodsId)?.GoodsName;
};
switch (operatorType)
{
case OutOrderOperType.EditOrder:
if (outStockEntitys.OutStatus != OutOderStatus.TodoAllot)
{
throw new CustomException($"当前状态为【{outStockEntitys.OutStatus.GetDescription()}】不可编辑。");
}
var outstockItems = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == outmodel.Id).ToList();
this.Context.RemoveRange(outstockItems);
//outStockEntitys = Mapper.Map<OutstockDemandBillEntity>(outmodel);
outStockEntitys.From(outmodel);
var upOutStoclItemEntity = Mapper.Map<List<OutstockDemandBillItemEntity>>(outmodel.Items);
upOutStoclItemEntity.ForEach(x =>
{
x.Id = Guid.NewGuid().ToString("N");
x.OutstockDemandBillId = outmodel.Id;
x.ActualOutQuantity = x.PlanOutQuantity;
x.ActualProductBatch = x.PlanProductBatch;
});
//this.Context.Set<OutstockDemandBillEntity>().Local.Clear();
//this.Context.Set<OutstockDemandBillEntity>().Local.Add(outStockEntitys);
//this.Context.Entry(outStockEntitys).State = EntityState.Modified;
this.Context.UpdateRange(outStockEntitys);
await this.Context.AddRangeAsync(upOutStoclItemEntity);
break;
case OutOrderOperType.AllotOrder:
if (outStockEntitys.OutStatus != OutOderStatus.TodoAllot)
{
throw new CustomException($"当前所传状态为【{outStockEntitys.OutStatus.GetDescription()}】不可进行任务分配操作。");
}
if (string.IsNullOrWhiteSpace(outmodel.OutstockGroup))
{
throw new CustomException("出库组不能为空!");
}
outmodel.Items.ForEach(x =>
{
if (string.IsNullOrWhiteSpace(x.PlanProductBatch))
{
throw new CustomException($"【{func(x.GoodsId)}】计划出库批号不能为空");
}
if (x.ActualOutQuantity <= 0)
{
throw new CustomException($"【{func(x.GoodsId)}-{x.PlanProductBatch}】实际出库数量需大于0");
}
});
outStockEntitys.OutstockGroup = outmodel.OutstockGroup;
outStockEntitys.OutStatus = OutOderStatus.DoneAllot;
outStockEntitys.TaskTime = System.DateTime.Now;
outStockEntitys.TaskUser = outmodel.Updator;
outStockEntitys.UpdateDate = System.DateTime.Now;
outStockEntitys.Updator = outmodel.Updator;
this.Context.Set<OutstockDemandBillEntity>().Update(outStockEntitys);
var upOutStockItemEntity = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == outmodel.Id).ToList();
upOutStockItemEntity.ForEach(x =>
{
x.PlanProductBatch = outmodel.Items.SingleOrDefault(y => y.Id == x.Id).PlanProductBatch;
x.ActualOutQuantity = outmodel.Items.SingleOrDefault(y => y.Id == x.Id).ActualOutQuantity;
x.ActualProductBatch = outmodel.Items.SingleOrDefault(y => y.Id == x.Id).ActualProductBatch;
if (string.IsNullOrWhiteSpace(x.ActualProductBatch))
{
x.ActualProductBatch = x.PlanProductBatch;
}
x.UpdateDate = System.DateTime.Now;
x.Updator = outmodel.Updator;
});
this.Context.Set<OutstockDemandBillItemEntity>().UpdateRange(upOutStockItemEntity);
break;
case OutOrderOperType.OutOder:
if (!(outStockEntitys.OutStatus == OutOderStatus.DoneAllot || outStockEntitys.OutStatus == OutOderStatus.OutBoundIng))
{
throw new CustomException($"当前所传状态为【{outStockEntitys.OutStatus.GetDescription()}】不可进行出库下架操作。");
}
//待下架完整单据的货物
var outStockItems = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == outmodel.Id).ToList();
if (outStockItems.Where(x => x.OffshelvesStatus == OutOderItemStatus.TodoOffshelves).Count() == 0)
{
throw new CustomException("所有货物已全部下架,请勿重复操作!");
}
//待出库的货物明细
var todoOutitems = outmodel.Items.Where(x => !string.IsNullOrWhiteSpace(x.OutstockLocation)
&& !string.IsNullOrWhiteSpace(x.ActualProductBatch) && x.ActualOutQuantity > 0).ToList();
if (todoOutitems.Count() == 0)
{
throw new CustomException("库位,实际出库批号,不能为空,且实际出库数量必须大于0");
}
todoOutitems = todoOutitems.Where(x => x.OffshelvesStatus == OutOderItemStatus.TodoOffshelves).ToList();
if (todoOutitems.Count() == 0)
{
throw new CustomException("所有货物已全部下架,请勿重复操作!");
}
//部分下架中存在部分重复出库情况验证处理
var offshelveseds = outStockItems.Where(x => x.OffshelvesStatus == OutOderItemStatus.DoneOffshelves);
if (offshelveseds.Count() > 0)
{
Func<string, string> funLocation = locationId => this.Context.Set<WareHouseLocationEntity>().SingleOrDefault(x => x.Id == locationId)?.LocationCode;
var reportDatas = offshelveseds.Where(y => todoOutitems.Select(x => x.Id).Contains(y.Id)).ToList();
if (reportDatas.Count() > 0)
{
var msg = string.Empty;
reportDatas.ForEach(x =>
{
msg +=$"{func(x.GoodsId)};批号:{ x.ActualProductBatch};库位:{funLocation(x.OutstockLocation)}," ;
});
throw new CustomException($"【{msg.TrimEnd(',')}】已经下架,请勿重复操作!");
}
}
//本次需要下架完整单据的货物
var upOutItems = outStockItems.Where(x => todoOutitems.Select(y => y.Id).Contains(x.Id)).ToList();
//判断本次操作是否整单全部下架
if (outStockItems.Where(x => x.OffshelvesStatus == OutOderItemStatus.DoneOffshelves).Count() + todoOutitems.Count() == outStockItems.Count())
{
outStockEntitys.OutStatus = OutOderStatus.DoneOutBound;
}
else
{
outStockEntitys.OutStatus = OutOderStatus.OutBoundIng;
}
outStockEntitys.UpdateDate = System.DateTime.Now;
outStockEntitys.Updator = outmodel.Updator;
this.Context.Update(outStockEntitys);
//修改出库明细下架信息
upOutItems.ForEach(x =>
{
x.ActualOutQuantity= todoOutitems.FirstOrDefault(y => y.Id == x.Id).ActualOutQuantity;
x.ActualProductBatch = todoOutitems.FirstOrDefault(y => y.Id == x.Id)?.ActualProductBatch;
x.OutstockLocation = todoOutitems.FirstOrDefault(y => y.Id == x.Id)?.OutstockLocation;
x.OffshelvesStatus = OutOderItemStatus.DoneOffshelves;
x.Offshelves = outmodel.Updator;
x.OffshelvesTime = DateTime.Now;
});
this.Context.UpdateRange(upOutItems);
#region 调库存接口
var todoMapOutStock = Mapper.Map<List<StockModel>>(upOutItems);
var todoAddStock= todoMapOutStock.Select(x =>
{
x.Id = string.Empty; x.BillNo = outmodel.DemandNo; x.AreaId = outmodel.AreaId;
x.CreateDate = System.DateTime.Now; x.Creator = outmodel.Creator; x.UpdateDate = System.DateTime.Now; x.Updator = outmodel.Updator; return x;
}).ToList();
await _stockService.AddStock(todoAddStock, this.Context, false);
#endregion
break;
}
var tran = Context.Database.BeginTransaction();
try
{
//提交事务操作数据
await Context.SaveChangesAsync();
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
throw new CustomException(ex.Message);
}
}
/// <summary>
/// /// <summary>
/// 条件获取出库单信息
/// </summary>
/// <param name="key">出库单号,主键Id,需求商Id</param>
/// <param name="areaId">库区编号</param>
/// <param name="outStatus">出库单状态</param>
/// <param name="startTime">预约开始时间</param>
/// <param name="endTime">预约结束时间</param>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页显示的值</param>
/// <returns></returns>
/// </summary>
public async Task<Page<OutstockDemandBillListModel>> GetPageList(string key, string areaId, int outStatus, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
{
Expression<Func<OutstockDemandBillEntity, bool>> where = m => m.IsDelete == DeleteStatus.Normal;
if (!string.IsNullOrWhiteSpace(key))
{
where = where.And(x => x.Id == key || x.DemanderId == key || x.DemandNo.Contains(key));
}
if (!string.IsNullOrWhiteSpace(areaId))
{
where = where.And(x => x.AreaId == areaId);
}
if (outStatus >= 0)
{
where = where.And(x => x.OutStatus == (OutOderStatus)outStatus);
}
if (startTime != null && endTime != null && startTime != DateTime.MinValue && endTime != DateTime.MinValue)
{
if (Convert.ToDateTime(startTime).Date > Convert.ToDateTime(endTime).Date)
{
throw new CustomException("开始时间不能大于结束时间");
}
}
if (startTime != null && startTime != DateTime.MinValue)
{
where = where.And(x => x.AppointmentDate > Convert.ToDateTime(startTime).Date);
}
if (endTime != null && endTime != DateTime.MinValue)
{
where = where.And(x => x.AppointmentDate < Convert.ToDateTime(endTime).AddDays(1).Date);
}
var query = this.Context.Set<OutstockDemandBillEntity>().Where(where);
pageIndex = pageIndex <= 0 ? 1 : pageIndex;
pageSize = pageSize <= 0 ? 10 : pageSize;
var amount = await query.CountAsync();
var totlePage = (amount - 1) / pageSize + 1;
if (pageIndex > totlePage)
{
pageIndex = totlePage;
}
query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
List<OutstockDemandBillListModel> rlist = new List<OutstockDemandBillListModel>();
if (query.Count() > 0)
{
rlist = Mapper.Map<List<OutstockDemandBillListModel>>(query.ToList());
if (rlist.Count() > 0)
{
var areaInfos = this.Context.Set<WareHouseAreaEntity>().Where(x => rlist.Select(y => y.AreaId).Contains(x.Id)).ToList();
var demanInfos = this.Context.Set<DemanderEntity>().Where(x => rlist.Select(y => y.DemanderId).Contains(x.Id)).ToList();
foreach (var item in rlist)
{
item.AreaName = areaInfos.FirstOrDefault(x => x.Id == item.AreaId)?.AreaName;
item.DemanderName = demanInfos.FirstOrDefault(x => x.Id == item.DemanderId)?.DemanderName;
}
}
}
var page = new Page<OutstockDemandBillListModel>() { Size = pageSize, Index = pageIndex, Amount = amount, Datas = rlist };
return page;
}
/// <summary>
/// 获取出库单明细
/// </summary>
/// <param name="key">关键字</param>
/// <returns></returns>
public OutstockDemandBillModel GetOutStockItemList(string key)
{
OutstockDemandBillModel rmodel = new OutstockDemandBillModel();
Func<string, string> funcArea = areaId =>
{
return this.Context.Set<WareHouseAreaEntity>().FirstOrDefault(x => x.Id.Equals(areaId))?.AreaName;
};
Func<string, string> funcDeman = demanId =>
{
return this.Context.Set<DemanderEntity>().FirstOrDefault(x => x.Id.Equals(demanId))?.DemanderName;
};
if (string.IsNullOrWhiteSpace(key))
{
throw new CustomException("传入参数不能为空!");
}
var rOderEntity = this.Context.Set<OutstockDemandBillEntity>().FirstOrDefault(x => x.Id == key && x.IsDelete == DeleteStatus.Normal);
if (rOderEntity == null)
{
throw new CustomException("未找到对应的出库单,请传入有效的查询参数!");
}
rmodel = Mapper.Map<OutstockDemandBillModel>(rOderEntity);
rmodel.AreaName = funcArea(rmodel.AreaId);
rmodel.DemanderName = funcDeman(rmodel.DemanderId);
var rOrderItems = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == key).ToList();
if (rOrderItems.Count() > 0)
{
rmodel.Items = Mapper.Map<List<OutstockDemandBillItemModel>>(rOrderItems);
}
return rmodel;
}
}
}