|
|
@ -1,11 +1,12 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Data.SqlClient; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Linq; |
|
|
|
using System.Linq.Dynamic.Core; |
|
|
|
using System.Text.Json; |
|
|
|
using System.Threading; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using EFCore.BulkExtensions; |
|
|
|
using Magicodes.ExporterAndImporter.Core.Extension; |
|
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
|
using Microsoft.EntityFrameworkCore; |
|
|
@ -29,6 +30,7 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
{ |
|
|
|
private readonly IServiceProvider _serviceProvider; |
|
|
|
private readonly ILogger<VmiAsyncBalanceService> _logger; |
|
|
|
private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); |
|
|
|
|
|
|
|
public VmiAsyncBalanceService(IServiceProvider serviceProvider, ILogger<VmiAsyncBalanceService> logger) |
|
|
|
{ |
|
|
@ -50,15 +52,30 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
|
|
|
|
[NonAction] |
|
|
|
public async Task Invoke(IServiceProvider serviceProvider) |
|
|
|
{ |
|
|
|
await semaphoreSlim.WaitAsync().ConfigureAwait(false); |
|
|
|
try |
|
|
|
{ |
|
|
|
await InvokeInternal(serviceProvider).ConfigureAwait(false); |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
semaphoreSlim.Release(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private async Task InvokeInternal(IServiceProvider serviceProvider) |
|
|
|
{ |
|
|
|
var batchSize = 1000; |
|
|
|
var fetchSize = 0; |
|
|
|
var connectionString = serviceProvider.GetRequiredService<IConfiguration>().GetConnectionString("SettleAccountService"); |
|
|
|
for (var i = 0; i < 1000; i++) |
|
|
|
{ |
|
|
|
var balanceList = new List<Tuple<VmiBalance, int>>(); |
|
|
|
var vmiReplenishedList = new List<VmiReplenished>(); |
|
|
|
var sw = new Stopwatch(); |
|
|
|
sw.Start(); |
|
|
|
using var connection = new SqlConnection(connectionString); |
|
|
|
using var connection = new Microsoft.Data.SqlClient.SqlConnection(connectionString); |
|
|
|
connection.Open(); |
|
|
|
using var transaction = connection.BeginTransaction(); |
|
|
|
try |
|
|
@ -72,20 +89,30 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
var vmiLogRepo = context.Set<VmiLog>(); |
|
|
|
var vmiBalanceRepo = context.Set<VmiBalance>(); |
|
|
|
var vmiReplenishedRepo = context.Set<VmiReplenished>(); |
|
|
|
if (!vmiMessageRepo.Any(o => !o.isConsumed)) |
|
|
|
//读取可消费消息列表
|
|
|
|
var messages = vmiMessageRepo.AsNoTracking().Where(o => !o.isConsumed).OrderBy(o => o.Number).Take(batchSize).ToList(); |
|
|
|
//没有可消费消息则返回
|
|
|
|
if (!messages.Any()) |
|
|
|
{ |
|
|
|
transaction.Commit(); |
|
|
|
break; |
|
|
|
} |
|
|
|
var messages = vmiMessageRepo.Where(o => !o.isConsumed).OrderBy(o => o.Number).Take(batchSize).ToList(); |
|
|
|
fetchSize=messages.Count; |
|
|
|
//设置数量为实际返回数量
|
|
|
|
fetchSize = messages.Count; |
|
|
|
//反序列化获取库存事务
|
|
|
|
var list = messages.Select(o => |
|
|
|
{ |
|
|
|
var log = JsonSerializer.Deserialize<VmiLog>(o.Message); |
|
|
|
log.SetId(Guid.Parse(JsonSerializer.Deserialize<JsonElement>(o.Message).GetProperty("Id").GetString())); |
|
|
|
return new KeyValuePair<VmiMessage, VmiLog>(o, log); |
|
|
|
}).ToDictionary(o => o.Key, o => o.Value); |
|
|
|
var tables = list.Values.Select(o => $"Set_VmiLog_{o.ChangedTime.Year}_{(o.ChangedTime.Month - 1) / 3 + 1}").Distinct().ToList(); |
|
|
|
var jsonElement = JsonSerializer.Deserialize<JsonElement>(o.Message); |
|
|
|
var property = jsonElement.GetProperty("Id"); |
|
|
|
Console.WriteLine(jsonElement); |
|
|
|
var id = Guid.Parse(property.GetString()); |
|
|
|
log.SetId(id); |
|
|
|
return new LogToBalance { VmiMessage = o, Log = log, Table = $"Set_VmiLog_{log.ChangedTime.Year}_{(log.ChangedTime.Month - 1) / 3 + 1}" }; |
|
|
|
}); |
|
|
|
//获取分表名称
|
|
|
|
var tables = list.Select(o => o.Table).Distinct().ToList(); |
|
|
|
//创建分表
|
|
|
|
foreach (var table in tables) |
|
|
|
{ |
|
|
|
command.CommandText = $"select OBJECT_ID('{table}', 'U')"; |
|
|
@ -100,17 +127,13 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
command.ExecuteNonQuery(); |
|
|
|
} |
|
|
|
} |
|
|
|
foreach (var keyValue in list) |
|
|
|
foreach (var item in list) |
|
|
|
{ |
|
|
|
var message = keyValue.Key; |
|
|
|
var log = keyValue.Value; |
|
|
|
//获取分表名
|
|
|
|
var table = $"Set_VmiLog_{log.ChangedTime.Year}_{(log.ChangedTime.Month - 1) / 3 + 1}"; |
|
|
|
//插入到分表
|
|
|
|
command.CommandText = $"insert into {table} select * from Set_VmiLog where id ='{log.Id}'"; |
|
|
|
command.ExecuteNonQuery(); |
|
|
|
//插入库存
|
|
|
|
var balance = vmiBalanceRepo.FirstOrDefault( |
|
|
|
var message = item.VmiMessage; |
|
|
|
message.isConsumed = true; |
|
|
|
var log = item.Log; |
|
|
|
//本地查找
|
|
|
|
var balance = balanceList.Select(o => o.Item1).FirstOrDefault( |
|
|
|
o => o.DeliverBillType == log.DeliverBillType && |
|
|
|
o.CodeType == log.CodeType && |
|
|
|
o.DeliverBillType == log.DeliverBillType && |
|
|
@ -119,10 +142,25 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
o.OrderNum == log.OrderNum && |
|
|
|
o.factory == log.factory && |
|
|
|
o.Configcode == log.Configcode); |
|
|
|
|
|
|
|
//数据库查找
|
|
|
|
if (balance == null) |
|
|
|
{ |
|
|
|
balance = vmiBalanceRepo.FirstOrDefault( |
|
|
|
o => o.DeliverBillType == log.DeliverBillType && |
|
|
|
o.CodeType == log.CodeType && |
|
|
|
o.DeliverBillType == log.DeliverBillType && |
|
|
|
o.VinCode == log.VinCode && |
|
|
|
o.ErpToLoc == log.ErpToLoc && |
|
|
|
o.OrderNum == log.OrderNum && |
|
|
|
o.factory == log.factory && |
|
|
|
o.Configcode == log.Configcode); |
|
|
|
} |
|
|
|
if (balance == null) |
|
|
|
{//不存在库存记录
|
|
|
|
//新建库存记录
|
|
|
|
balance = new VmiBalance(); |
|
|
|
balanceList.Add(new Tuple<VmiBalance, int>(balance, 1)); |
|
|
|
if (log.LogType == VmiLogType.Type300) |
|
|
|
{//反结算入库,重建库存
|
|
|
|
var logHistory = vmiLogRepo.AsNoTracking().FirstOrDefault( |
|
|
@ -149,10 +187,13 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
balance.InjectFrom(log); |
|
|
|
} |
|
|
|
balance.Qty = log.ChangedQty; |
|
|
|
await vmiBalanceRepo.AddAsync(balance).ConfigureAwait(false); |
|
|
|
} |
|
|
|
else |
|
|
|
{//存在库存记录
|
|
|
|
if (!balanceList.Any(o => o.Item1.Id == balance.Id)) |
|
|
|
{ |
|
|
|
balanceList.Add(new Tuple<VmiBalance, int>(balance, 2)); |
|
|
|
} |
|
|
|
var logType = log.LogType; |
|
|
|
var currentQty = balance.Qty;// + log.ty
|
|
|
|
if (logType == VmiLogType.Type100) |
|
|
@ -177,7 +218,7 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
//添加负库存补货记录
|
|
|
|
var log2 = new VmiReplenished(); |
|
|
|
log2.InjectFrom(log); |
|
|
|
await vmiReplenishedRepo.AddAsync(log2).ConfigureAwait(false); |
|
|
|
vmiReplenishedList.Add(log2); |
|
|
|
} |
|
|
|
// 更新库存
|
|
|
|
balance.Qty = currentQty + log.ChangedQty; |
|
|
@ -187,9 +228,40 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
vmiBalanceRepo.Remove(balance); |
|
|
|
} |
|
|
|
} |
|
|
|
message.isConsumed = true; |
|
|
|
context.SaveChanges(); |
|
|
|
} |
|
|
|
|
|
|
|
//更新事务分表
|
|
|
|
//foreach (var item in tables)
|
|
|
|
//{
|
|
|
|
// var logs = list.Where(o => o.Table == item).Select(o => o.Log).ToList();
|
|
|
|
// var xxx= logs.Select(o=>o.Id).Distinct().ToList();
|
|
|
|
// await context.BulkInsertAsync(logs, new BulkConfig
|
|
|
|
// {
|
|
|
|
// CustomDestinationTableName = item,
|
|
|
|
// }).ConfigureAwait(false);
|
|
|
|
//}
|
|
|
|
//批量更新消息
|
|
|
|
await context.BulkUpdateAsync(messages, new BulkConfig |
|
|
|
{ |
|
|
|
PropertiesToExclude = new List<string> { nameof(VmiMessage.Number) } |
|
|
|
}).ConfigureAwait(false); |
|
|
|
//批量插入负库存补货记录
|
|
|
|
await context.BulkInsertAsync(vmiReplenishedList).ConfigureAwait(false); |
|
|
|
//批量插入库存余额
|
|
|
|
var addList = balanceList.Where(o => o.Item2 == 1 && o.Item1.Qty != decimal.Zero).Select(o => o.Item1).ToList(); |
|
|
|
var test0 = addList.Count; |
|
|
|
var test1 = addList.Select(o => o.Id).Distinct().Count(); |
|
|
|
await context.BulkInsertAsync(balanceList.Where(o => o.Item2 == 1 && o.Item1.Qty != decimal.Zero).Select(o => o.Item1).ToList()).ConfigureAwait(false); |
|
|
|
//批量更新库存余额
|
|
|
|
var updateList = balanceList.Where(o => o.Item2 == 2 && o.Item1.Qty != decimal.Zero).Select(o => o.Item1).ToList(); |
|
|
|
var test20 = updateList.Count; |
|
|
|
var test21 = updateList.Select(o => o.Id).Distinct().Count(); |
|
|
|
await context.BulkUpdateAsync(balanceList.Where(o => o.Item2 == 2 && o.Item1.Qty != decimal.Zero).Select(o => o.Item1).ToList()).ConfigureAwait(false); |
|
|
|
//批量删除库存余额
|
|
|
|
var deleteList = balanceList.Where(o => o.Item2 == 2 && o.Item1.Qty == decimal.Zero).Select(o => o.Item1).ToList(); |
|
|
|
var test30 = addList.Count; |
|
|
|
var test31 = addList.Select(o => o.Id).Distinct().Count(); |
|
|
|
await context.BulkDeleteAsync(balanceList.Where(o => o.Item2 == 2 && o.Item1.Qty == decimal.Zero).Select(o => o.Item1).ToList()).ConfigureAwait(false); |
|
|
|
transaction.Commit(); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
@ -205,3 +277,10 @@ public class VmiAsyncBalanceService : Controller, IApplicationService, IJobServi |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class LogToBalance |
|
|
|
{ |
|
|
|
public VmiMessage VmiMessage { get; set; } |
|
|
|
public VmiLog Log { get; set; } |
|
|
|
public string Table { get; set; } |
|
|
|
} |
|
|
|