From 9fcff337cb74e5c41319d6ccc98a26a281368e0e Mon Sep 17 00:00:00 2001 From: liuyuanjin <1107290929@qq.com> Date: Sat, 28 Dec 2024 18:09:39 +0800 Subject: [PATCH 1/3] =?UTF-8?q?pref:=E5=8F=96=E6=B6=88=E6=8A=98=E6=97=A7?= =?UTF-8?q?=E9=99=90=E5=88=B6=EF=BC=8C=E7=94=B1=E5=89=8D=E7=AB=AF=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=98=AF=E5=90=A6=E5=8F=AF=E6=8A=98=E6=97=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/ThingDepreciationService.cs | 42 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Services/ThingDepreciationService.cs b/Services/ThingDepreciationService.cs index 073282b..b873766 100644 --- a/Services/ThingDepreciationService.cs +++ b/Services/ThingDepreciationService.cs @@ -147,27 +147,27 @@ public class ThingDepreciationService : ITransient { return OperateResult.Faild($"{period.Period} 已折旧!"); } - if (args.Type == "Confirm") - { - var coll = provider.TryGetCollection(token, "_system-things"); - if (coll.success) - { - var filter = Builders.Filter.And( - Builders.Filter.Eq("belongId", token.BelongId.ToString()), - Builders.Filter.Eq("isDeleted", false), - Builders.Filter.Exists("locks") - ); - var count = await coll.data.Find(filter).Limit(1).CountDocumentsAsync(); - if (count > 0) - { - return OperateResult.Faild($"存在锁定中资产,业务完结后可确认折旧!"); - } - } - else - { - return OperateResult.Faild($"获取 _system-things 集合失败!"); - } - } + // if (args.Type == "Confirm") + // { + // var coll = provider.TryGetCollection(token, "_system-things"); + // if (coll.success) + // { + // var filter = Builders.Filter.And( + // Builders.Filter.Eq("belongId", token.BelongId.ToString()), + // Builders.Filter.Eq("isDeleted", false), + // Builders.Filter.Exists("locks") + // ); + // var count = await coll.data.Find(filter).Limit(1).CountDocumentsAsync(); + // if (count > 0) + // { + // return OperateResult.Faild($"存在锁定中资产,业务完结后可确认折旧!"); + // } + // } + // else + // { + // return OperateResult.Faild($"获取 _system-things 集合失败!"); + // } + // } break; case "Revoke": if (!(period.depreciated ?? false)) -- Gitee From a55ef37b408e2533a6ac302a5fe2c381abdb4468 Mon Sep 17 00:00:00 2001 From: liuyuanjin <1107290929@qq.com> Date: Wed, 7 Jan 2026 18:23:28 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=E6=9F=A5=E8=AF=A2=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E6=8A=98=E6=97=A7=E7=9A=84=E8=B5=84=E4=BA=A7=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Entitys/XDepreciationConfig.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Entitys/XDepreciationConfig.cs b/Entitys/XDepreciationConfig.cs index 7a4cc84..d1180dc 100644 --- a/Entitys/XDepreciationConfig.cs +++ b/Entitys/XDepreciationConfig.cs @@ -23,7 +23,7 @@ namespace anydata.Models public XProperty? ResidualRate { get; set; } public XProperty? ResidualVal { get; set; } public List Fields { get; set; } - + public bool Check() { @@ -57,6 +57,10 @@ namespace anydata.Models public JToken BuildQuery(TokenModel token) { + var methods = new JArray(); + if (YearAverageMethod != null) methods.Add(YearAverageMethod); + if (YearAverageMethod2 != null) methods.Add(YearAverageMethod2); + return new JObject { ["match"] = new JObject @@ -65,11 +69,7 @@ namespace anydata.Models ["belongId"] = token.BelongId.ToString(), [DepreciationMethod.field.code] = new JObject { - ["_in_"] = new JArray - { - YearAverageMethod, - YearAverageMethod2 - } + ["_in_"] = methods }, [OriginalValue.field.code] = new JObject { @@ -174,7 +174,7 @@ namespace anydata.Models var remainderMonth = usefulLife - rightAccruedMonths; if (remainderMonth <= 0 || netWorth < residualVal) { - afterAccumulated = originalValue-residualVal; + afterAccumulated = originalValue - residualVal; afterNetWorth = residualVal; if (Math.Round(afterAccumulated, 2) != Math.Round(accumulated, 2)) { -- Gitee From e2fb06294650cdb4879870f91b1d3cc3448b2224 Mon Sep 17 00:00:00 2001 From: liuyuanjin <1107290929@qq.com> Date: Fri, 9 Jan 2026 15:02:43 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=E6=95=B0=E6=8D=AE=E6=A0=B8=E6=8A=98?= =?UTF-8?q?=E6=97=A7=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=BB=BA=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Models/DepreciationContext.cs | 4 +++ Providers/DataProvider.cs | 5 +++ Services/ThingDepreciationService.cs | 47 ++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/Models/DepreciationContext.cs b/Models/DepreciationContext.cs index d3a72f1..9fce675 100644 --- a/Models/DepreciationContext.cs +++ b/Models/DepreciationContext.cs @@ -42,6 +42,10 @@ namespace anydata.Models }; } + /** + * TODO: + * 1. 用 instanceId、belongId 创建索引 + */ public JToken BuildMatch() { return new JObject() diff --git a/Providers/DataProvider.cs b/Providers/DataProvider.cs index 72228a3..d12df54 100644 --- a/Providers/DataProvider.cs +++ b/Providers/DataProvider.cs @@ -11,6 +11,11 @@ namespace anydata.Providers { readonly MongoStorage storage; readonly IServiceProvider services; + + /** + * TODO: + * 1. 给 _system-things 、_system-things-changed、_system-things-snapshot 添加索引(默认只有一个id索引) + */ public const string ThingCollName = "_system-things"; public const string ChangeCollName = "_system-things-changed"; public const string SnapshotCollName = "_system-things-snapshot"; diff --git a/Services/ThingDepreciationService.cs b/Services/ThingDepreciationService.cs index a2edcff..a23a29b 100644 --- a/Services/ThingDepreciationService.cs +++ b/Services/ThingDepreciationService.cs @@ -59,6 +59,11 @@ public class ThingDepreciationService : ITransient if (context.HasRecord) { var options = BuildOptions(context, things.Select(item => item.id).ToList()); + /* + * TODO: + * 1. 批量查询优化:使用 `$in` 操作符一次性查询所有 ID,但要注意分批处理(MongoDB 的 $in 限制为 1000 个) + * 2. 使用字典缓存:将查询结果转换为 Dictionary 以提高查找效率 + */ var result = await provider.LoadAsync(context.Token, DataProvider.ThingCollName, options); if (!result.success) { @@ -67,6 +72,7 @@ public class ThingDepreciationService : ITransient var oldThings = ((result.data as LoadResult)?.data as List) ?? new List(); foreach (var newThing in things) { + // TODO: 3. 使用字典缓存 var oldThing = oldThings.Find(a => a.id == newThing.id); var snapshot = new XSnapshot(oldThing ?? newThing, context.Instance); changes.AddRange(XChange.CompareThing(context, oldThing, newThing.isDeleted == true ? null : newThing, snapshot.id)); @@ -200,6 +206,11 @@ public class ThingDepreciationService : ITransient await ClearSnapshot(context); if (total > 0) { + /* + * TODO: + * 1. 降低更新频率:不是每批都更新,而是每处理 N 批或每隔 X 秒更新一次 + * 2. 使用后台队列:将进度更新放入队列,异步批量处理 + */ await StartDepreciation(context, confirm, total, async (skip) => { await provider.UpdateOperationProgress(context.Token, context.OperationLog.id, skip, total); @@ -228,6 +239,10 @@ public class ThingDepreciationService : ITransient private async Task CountQuery(DepreciationContext context) { + /** + * TODO: + * 1.使用 CountDocumentsAsync 代替 LoadAsync + */ var loadOptions = new DataSourceLoadOptions() { options = context.Config.BuildQuery(context.Token), isCountQuery = true }; var result = await provider.LoadAsync(context.Token, DataProvider.ThingCollName, loadOptions); return ((LoadResult)result.data).totalCount; @@ -235,6 +250,10 @@ public class ThingDepreciationService : ITransient private async Task WorkCountQuery(DepreciationContext context) { + /** + * TODO: + * 1.使用 CountDocumentsAsync 代替 LoadAsync + */ var loadOptions = new DataSourceLoadOptions() { options = context.BuildWorkQuery(), isCountQuery = true }; var result = await provider.LoadAsync(context.Token, DataProvider.SnapshotCollName, loadOptions); return ((LoadResult)result.data).totalCount; @@ -252,6 +271,11 @@ public class ThingDepreciationService : ITransient private async Task UpdateThings(DepreciationContext context, List things) { + /* + * TODO: + * 1. 使用批量更新(BulkWrite):将多个 UpdateOne 操作合并为一次 BulkWrite 操作(分批处理) + * 2. 减少数据库往返次数:从 N 次数据库调用减少到 1 次数据库调用 + */ var coll = provider.TryGetCollection(context.Token, DataProvider.ThingCollName); if (coll.success) { @@ -273,8 +297,19 @@ public class ThingDepreciationService : ITransient int skip = 0, take = 300; while (skip < totalCount) { + /* + * TODO: + * 1. 移除 Thread.Sleep:这会阻塞线程,降低吞吐量 + * 2. 如果需要限流,使用异步延迟:`await Task.Delay(10)` 而不是 `Thread.Sleep(10)` + */ Thread.Sleep(10); var options = new DataSourceLoadOptions() { options = context.Config.BuildQuery(context.Token), take = take, skip = skip }; + /* + * TODO: + * 1. 使用投影(Projection):只查询需要的字段,而不是加载整个 EntityBase 对象 + * 2. 添加复合索引:确保集合(_system-things)创建索引,注意复合索引的字段顺序 + * 3. 使用游标(Cursor)代替 skip/take:对于大数据量,skip 会导致数据库扫描大量文档 + */ var result = await provider.LoadAsync(context.Token, DataProvider.ThingCollName, options); if (result.success && result.data != null) { @@ -284,6 +319,12 @@ public class ThingDepreciationService : ITransient List snapshots = new(); List endThings = new(); List allChanges = new(); + + /** + * TODO: + * 1. 使用并行处理(Parallel.ForEach 或 PLINQ):折旧计算是 CPU 密集型操作,可以并行化 + * 2. 使用线程安全的集合:如 ConcurrentBag + */ foreach (var before in oldThings) { var snapshot = new XSnapshot(before, context.Instance); @@ -297,6 +338,7 @@ public class ThingDepreciationService : ITransient } if (snapshots?.Count > 0) { + // TODO: 考虑使用 InsertManyAsync 的 ordered: false 选项,提高并发性能 await provider.InsertAsync(context.Token, DataProvider.SnapshotCollName, JToken.FromObject(snapshots)); } if (!confirm) @@ -305,11 +347,16 @@ public class ThingDepreciationService : ITransient } if (allChanges?.Count > 0) { + // TODO: 考虑使用 InsertManyAsync 的 ordered: false 选项,提高并发性能 await provider.InsertAsync(context.Token, DataProvider.ChangeCollName, JToken.FromObject(allChanges)); } if (confirm) { await UpdateThings(context, endThings); + /** + * TODO: + * 1.考虑延迟锁定:在所有计算完成后统一锁定,减少锁持有时间 + */ await lockService.LockThings(context.Token, context.Instance, DataProvider.ThingCollName, endThings.Select(a => a.id).ToList()); } if (oldThings.Count < take) -- Gitee