From eea309c1338ab5b5100c76ac9fb6a800f7a2d04c Mon Sep 17 00:00:00 2001 From: Soar360 Date: Tue, 3 Sep 2024 10:40:50 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20KeyedLocker=20?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E9=94=81=E5=AD=97=E7=AC=A6=E4=B8=B2=E9=80=A0?= =?UTF-8?q?=E6=88=90=E7=9A=84=E9=94=81=E5=AE=9A=E5=A4=B1=E8=B4=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XCode/Common/KeyedLocker.cs | 29 +++++++++++++++++++++++++++++ XCode/Entity/Entity.cs | 6 ++---- 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 XCode/Common/KeyedLocker.cs diff --git a/XCode/Common/KeyedLocker.cs b/XCode/Common/KeyedLocker.cs new file mode 100644 index 000000000..99a45da5a --- /dev/null +++ b/XCode/Common/KeyedLocker.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace XCode.Common; + +/// +/// 基于键的锁定器 +/// +internal class KeyedLocker +{ + private static object[] Lockers; + static KeyedLocker() + { + int Length = 8; + var temp = new object[Length]; + for (int i = 0; i < Length; i++) temp[i] = new object(); + Lockers = temp; + } + + public static object SharedLock(string key) + { + if (key is null) throw new ArgumentNullException(nameof(key)); + var code = key.GetHashCode(); + return Lockers[Math.Abs(code % Lockers.Length)]; + } +} diff --git a/XCode/Entity/Entity.cs b/XCode/Entity/Entity.cs index 497d8ab00..72022e9b5 100644 --- a/XCode/Entity/Entity.cs +++ b/XCode/Entity/Entity.cs @@ -2046,8 +2046,7 @@ public static TEntity GetOrAdd(TKey key, Func fin if (entity != null) return entity; // 加锁,避免同一个key并发新增 - var keyLock = $"{typeof(TEntity).FullName}-{key}"; - lock (keyLock) + lock (KeyedLocker.SharedLock(key!.ToString())) { // 打开事务,提升可靠性也避免读写分离造成数据不一致 using var trans = Meta.CreateTrans(); @@ -2096,8 +2095,7 @@ public static TEntity GetOrAdd(TKey key, Func find, Func.SharedLock(key!.ToString())) { // 打开事务,提升可靠性也避免读写分离造成数据不一致 using var trans = Meta.CreateTrans(); From 0b24d1f5c6921c6ebe56f16ea99c1466d23a34b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E7=9F=B3=E5=A4=B4?= Date: Wed, 4 Sep 2024 14:31:15 +0800 Subject: [PATCH 2/3] =?UTF-8?q?[improv]=E8=8F=9C=E5=8D=95=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=EF=BC=8C=E4=BB=85=E4=BA=A4=E6=8D=A2=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E8=A6=81=E7=BB=99=E6=89=80=E6=9C=89=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E9=87=8D=E6=96=B0=E8=AE=A1=E7=AE=97=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E6=95=B0=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XCode/Tree/EntityTree.cs | 136 +++++++++++++++++++++++--------------- XCode/Tree/IEntityTree.cs | 46 ++++++------- 2 files changed, 103 insertions(+), 79 deletions(-) diff --git a/XCode/Tree/EntityTree.cs b/XCode/Tree/EntityTree.cs index d31a17dfe..224b5d620 100644 --- a/XCode/Tree/EntityTree.cs +++ b/XCode/Tree/EntityTree.cs @@ -37,45 +37,45 @@ static EntityTree() } /// 实体树操作者 - protected static IEntityTreeSetting Setting; + public static IEntityTreeSetting Setting; #endregion #region 扩展属性 /// 排序值 private Int32 Sort { - get { return String.IsNullOrEmpty(Setting.Sort) ? 0 : (Int32)this[Setting.Sort]; } - set { if (!String.IsNullOrEmpty(Setting.Sort) && (Int32)this[Setting.Sort] != value) SetItem(Setting.Sort, value); } + get { return String.IsNullOrEmpty(Setting.Sort) ? 0 : (Int32)this[Setting.Sort]!; } + set { if (!String.IsNullOrEmpty(Setting.Sort) && (Int32)this[Setting.Sort]! != value) SetItem(Setting.Sort, value); } } /// 子节点 [XmlIgnore, ScriptIgnore, IgnoreDataMember] - public virtual IList Childs => Extends.Get(nameof(Childs), e => FindChilds()); + public virtual IList Childs => Extends.Get(nameof(Childs), e => FindChilds())!; /// 子节点 - protected virtual IList FindChilds() => FindAllByParent((TKey)this[Setting.Key]); + protected virtual IList FindChilds() => FindAllByParent((TKey)this[Setting.Key]!); /// 父节点 [XmlIgnore, ScriptIgnore, IgnoreDataMember] - public virtual TEntity Parent => Extends.Get(nameof(Parent), e => FindParent()); + public virtual TEntity? Parent => Extends.Get(nameof(Parent), e => FindParent()); /// 父节点 - protected virtual TEntity FindParent() => FindByKeyWithCache((TKey)this[Setting.Parent]); + protected virtual TEntity FindParent() => FindByKeyWithCache((TKey)this[Setting.Parent]!); /// 在缓存中查找节点 protected static TEntity FindByKeyWithCache(TKey key) => Meta.Session.Cache.Find(e => Equals(e[Setting.Key], key)); /// 子孙节点 [XmlIgnore, ScriptIgnore, IgnoreDataMember] - public virtual IList AllChilds => Extends.Get(nameof(AllChilds), e => FindAllChilds(this)); + public virtual IList AllChilds => Extends.Get(nameof(AllChilds), e => FindAllChilds(this))!; /// 子孙节点,包含自己 [XmlIgnore, ScriptIgnore, IgnoreDataMember] - public virtual IList MyAllChilds => Extends.Get(nameof(MyAllChilds), e => FindAllChilds(this, true)); + public virtual IList MyAllChilds => Extends.Get(nameof(MyAllChilds), e => FindAllChilds(this, true))!; /// 父节点集合 [XmlIgnore, ScriptIgnore, IgnoreDataMember] - public virtual IList AllParents => Extends.Get(nameof(AllParents), e => FindAllParents(this)); + public virtual IList AllParents => Extends.Get(nameof(AllParents), e => FindAllParents(this))!; /// 深度 [XmlIgnore, ScriptIgnore, IgnoreDataMember] @@ -92,7 +92,7 @@ public virtual Int32 Deepth } } - private static TEntity _Root; + private static TEntity _Root = null!; /// public static TEntity Root { @@ -101,29 +101,29 @@ public static TEntity Root if (_Root == null) { _Root = new TEntity(); - Meta.Session.OnDataChange += delegate { _Root = null; }; + Meta.Session.OnDataChange += delegate { _Root = null!; }; } return _Root; } - set { _Root = null; } + set { _Root = null!; } } /// 节点名 [XmlIgnore, ScriptIgnore, IgnoreDataMember] - public virtual String NodeName + public virtual String? NodeName { get { var key = Setting.Name; if (String.IsNullOrEmpty(key)) return String.Empty; - return (String)this[key]; + return (String?)this[key]; } } /// 父级节点名 [XmlIgnore, ScriptIgnore, IgnoreDataMember] - public virtual String ParentNodeName + public virtual String? ParentNodeName { get { @@ -133,7 +133,7 @@ public virtual String ParentNodeName var parent = Parent; if (parent == null) return String.Empty; - return (String)parent[key]; + return (String?)parent[key]; } } @@ -225,7 +225,7 @@ public static IList FindAllByParent(TKey parentKey) if (item1.Sort != item2.Sort) return -n * item1.Sort.CompareTo(item2.Sort); else - return (item1[Setting.Key] as IComparable).CompareTo(item2[Setting.Key]); + return (item1[Setting.Key] as IComparable)!.CompareTo(item2[Setting.Key]); }); } return list; @@ -236,7 +236,7 @@ public static IList FindAllByParent(TKey parentKey) public static IList FindAllNoParent() { // 有父节点的跳过,父节点为空的跳过 - return Meta.Session.Cache.FindAll(e => !IsNull((TKey)e[Setting.Parent]) && e.Parent == null); + return Meta.Session.Cache.FindAll(e => !IsNull((TKey)e[Setting.Parent]!) && e.Parent == null); } /// 查找指定键的所有子节点,以深度层次树结构输出,包括当前节点作为根节点。空父节点返回顶级列表,无效父节点返回空列表 @@ -246,7 +246,7 @@ public static IList FindAllNoParent() public static IList FindAllChildsByParent(TKey parentKey) { var entity = IsNull(parentKey) ? Root : FindByKeyWithCache(parentKey); - if (entity == null) return new List(); + if (entity == null) return []; return FindAllChilds(entity, true); } @@ -258,7 +258,7 @@ public static IList FindAllChildsByParent(TKey parentKey) public static IList FindAllChildsNoParent(TKey parentKey) { var entity = IsNull(parentKey) ? Root : FindByKeyWithCache(parentKey); - if (entity == null) return new List(); + if (entity == null) return []; return FindAllChilds(entity, false); } @@ -274,10 +274,10 @@ public static IList FindAllChildsNoParent(TKey parentKey) [DataObjectMethod(DataObjectMethodType.Select)] public static IList FindAllParentsByKey(TKey key) { - if (IsNull(key)) return new List(); + if (IsNull(key)) return []; var entity = FindByKeyWithCache(key); - if (entity == null) return new List(); + if (entity == null) return []; return FindAllParents(entity); } @@ -289,17 +289,17 @@ public static IList FindAllParentsByKey(TKey key) /// 返回列表是否包含根节点,默认false /// 要排除的节点 /// - protected static IList FindAllChilds(IEntityTree entity, Boolean includeSelf = false, IEntityTree exclude = null) + protected static IList FindAllChilds(IEntityTree entity, Boolean includeSelf = false, IEntityTree? exclude = null) { - if (entity == null) return new List(); + if (entity == null) return []; var childlist = entity.Childs; - if (childlist == null) return new List(); + if (childlist == null) return []; var list = new List(); // 不使用递归,避免死循环 // 使用堆栈而不使用队列,因为树的构造一般是深度搜索而不是广度搜索 var stack = new Stack(); - stack.Push(entity as TEntity); + stack.Push((entity as TEntity)!); while (stack.Count > 0) { @@ -337,7 +337,7 @@ protected static IList FindAllChilds(IEntityTree entity, Boolean includ protected static IList FindAllParents(IEntityTree entity, Boolean includeSelf = false) { var pkey = Setting.Parent; - if (entity == null || pkey.IsNullOrEmpty() || IsNull((TKey)entity[pkey]) || entity.Parent == null) return new List(); + if (entity == null || pkey.IsNullOrEmpty() || IsNull((TKey)entity[pkey]!) || entity.Parent == null) return []; var list = new List(); var item = entity as TEntity; @@ -363,7 +363,7 @@ protected static IList FindAllParents(IEntityTree entity, Boolean inclu /// 层次路径 /// 用于在每一层匹配实体的键值,默认是NameKeyName /// - public TEntity FindByPath(String path, params String[] keys) + public TEntity? FindByPath(String path, params String[] keys) { if (String.IsNullOrEmpty(path)) return null; @@ -386,11 +386,11 @@ public TEntity FindByPath(String path, params String[] keys) if (ss == null || ss.Length <= 0) return null; // 找第一级 - TEntity entity = null; + TEntity? entity = null; foreach (var item in keys) { //entity = list.Find(item, ss[0]); - entity = list.FirstOrDefault(e => (String)e[item] == ss[0]); + entity = list.FirstOrDefault(e => (String?)e[item] == ss[0]); if (entity != null) break; } if (entity == null) return null; @@ -413,7 +413,7 @@ public Boolean Contains(TKey key) if (IsNull(key)) return false; // 自身 - if (Equals((TKey)this[Setting.Key], key)) return true; + if (Equals((TKey)this[Setting.Key]!, key)) return true; // 子级 var list = Childs; @@ -433,7 +433,7 @@ public Boolean Contains(TKey key) /// 分隔符 /// 回调 /// - public String GetFullPath(Boolean includeSelf = true, String separator = @"\", Func func = null) + public String? GetFullPath(Boolean includeSelf = true, String separator = @"\", Func? func = null) { var list = FindAllParents(this, includeSelf); if (list == null || list.Count <= 0) return null; @@ -502,41 +502,69 @@ public virtual void ClearRelation() /// 排序上升 public void Up() { - var list = FindAllByParent((TKey)this[Setting.Parent]); + var list = FindAllByParent((TKey)this[Setting.Parent]!); if (list == null || list.Count <= 0) return; - var n = Setting.BigSort ? 1 : -1; + //var n = Setting.BigSort ? 1 : -1; + //for (var i = 0; i < list.Count; i++) + //{ + // var s = list.Count - i; + // // 当前项,排序增加。原来比较实体相等有问题,也许新旧实体类不对应,现在改为比较主键值 + // if (EqualTo(list[i])) s += n; + // // 下一项是当前项,排序减少 + // if (i < list.Count - 1 && EqualTo(list[i + 1])) s -= n; + // list[i].Sort = s; + //} + //list.Save(); + + // 跟前一个交换位置 for (var i = 0; i < list.Count; i++) { - var s = list.Count - i; - // 当前项,排序增加。原来比较实体相等有问题,也许新旧实体类不对应,现在改为比较主键值 - if (EqualTo(list[i])) s += n; - // 下一项是当前项,排序减少 - if (i < list.Count - 1 && EqualTo(list[i + 1])) s -= n; - list[i].Sort = s; + var cur = list[i]; + if (i > 1 && EqualTo(cur)) + { + var prev = list[i - 1]; + (prev.Sort, cur.Sort) = (cur.Sort, prev.Sort); + + cur.Update(); + prev.Update(); + } } - list.Save(); } /// 排序下降 public void Down() { - var list = FindAllByParent((TKey)this[Setting.Parent]); + var list = FindAllByParent((TKey)this[Setting.Parent]!); if (list == null || list.Count <= 0) return; - var n = Setting.BigSort ? 1 : -1; + //var n = Setting.BigSort ? 1 : -1; + //for (var i = 0; i < list.Count; i++) + //{ + // var s = list.Count - i; + // // 当前项,排序减少 + // if (EqualTo(list[i])) s -= n; + // // 上一项是当前项,排序增加 + // if (i >= 1 && EqualTo(list[i - 1])) s += n; + // list[i].Sort = s; + //} + //list.Save(); + + // 跟前一个交换位置 for (var i = 0; i < list.Count; i++) { - var s = list.Count - i; - // 当前项,排序减少 - if (EqualTo(list[i])) s -= n; - // 上一项是当前项,排序增加 - if (i >= 1 && EqualTo(list[i - 1])) s += n; - list[i].Sort = s; + var cur = list[i]; + if (i < list.Count - 1 && EqualTo(cur)) + { + var next = list[i + 1]; + (next.Sort, cur.Sort) = (cur.Sort, next.Sort); + + cur.Update(); + next.Update(); + } } - list.Save(); } Boolean EqualTo(IEntity entity) @@ -560,8 +588,8 @@ public override Boolean Valid(DataMethod method) if (!base.Valid(method)) return false; - var key = (TKey)this[Setting.Key]; - var pkey = (TKey)this[Setting.Parent]; + var key = (TKey)this[Setting.Key]!; + var pkey = (TKey)this[Setting.Parent]!; var isnull = IsNull(key); var pisnull = IsNull(pkey); @@ -624,7 +652,7 @@ private static Boolean IsNull(TKey value) #region IEntityTree 成员 /// 父实体 - IEntity IEntityTree.Parent => Parent; + IEntity? IEntityTree.Parent => Parent; /// 子实体集合 IList IEntityTree.Childs => Childs.Cast().ToList(); diff --git a/XCode/Tree/IEntityTree.cs b/XCode/Tree/IEntityTree.cs index 66ff01fa1..4483ac549 100644 --- a/XCode/Tree/IEntityTree.cs +++ b/XCode/Tree/IEntityTree.cs @@ -1,34 +1,30 @@ -using System; -using System.Collections.Generic; +namespace XCode; -namespace XCode +/// 实体树接口 +public interface IEntityTree : IEntity { - /// 实体树接口 - public interface IEntityTree : IEntity - { - #region 属性 - /// 父实体 - IEntity Parent { get; } + #region 属性 + /// 父实体 + IEntity? Parent { get; } - /// 子实体集合 - IList Childs { get; } + /// 子实体集合 + IList Childs { get; } - /// 子孙实体集合。以深度层次树结构输出 - IList AllChilds { get; } + /// 子孙实体集合。以深度层次树结构输出 + IList AllChilds { get; } - /// 父亲实体集合。以深度层次树结构输出 - IList AllParents { get; } + /// 父亲实体集合。以深度层次树结构输出 + IList AllParents { get; } - /// 深度 - Int32 Deepth { get; } + /// 深度 + Int32 Deepth { get; } - /// 树形节点名,根据深度带全角空格前缀 - String TreeNodeText { get; } + /// 树形节点名,根据深度带全角空格前缀 + String TreeNodeText { get; } - /// 获取完整树,包含根节点,排除指定分支。多用于树节点父级选择 - /// - /// - IList FindAllChildsExcept(IEntityTree exclude); - #endregion - } + /// 获取完整树,包含根节点,排除指定分支。多用于树节点父级选择 + /// + /// + IList FindAllChildsExcept(IEntityTree exclude); + #endregion } \ No newline at end of file From 90be67d6ed1bdca0af69a607190325e572687c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E7=9F=B3=E5=A4=B4?= Date: Wed, 4 Sep 2024 15:10:01 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=AE=9E=E4=BD=93=E6=A0=91FindAllChilds?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0depth=EF=BC=8C=E6=94=AF=E6=8C=81=E4=BB=85?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=8C=87=E5=AE=9A=E6=B7=B1=E5=BA=A6=E5=B1=82?= =?UTF-8?q?=E7=BA=A7=E7=9A=84=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XCode/Tree/EntityTree.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/XCode/Tree/EntityTree.cs b/XCode/Tree/EntityTree.cs index 224b5d620..feb847ea7 100644 --- a/XCode/Tree/EntityTree.cs +++ b/XCode/Tree/EntityTree.cs @@ -288,8 +288,9 @@ public static IList FindAllParentsByKey(TKey key) /// 根节点 /// 返回列表是否包含根节点,默认false /// 要排除的节点 + /// 深度。仅返回指定深度层级的节点 /// - protected static IList FindAllChilds(IEntityTree entity, Boolean includeSelf = false, IEntityTree? exclude = null) + public static IList FindAllChilds(IEntityTree entity, Boolean includeSelf = false, IEntityTree? exclude = null, Int32 depth = -1) { if (entity == null) return []; var childlist = entity.Childs; @@ -321,7 +322,7 @@ protected static IList FindAllChilds(IEntityTree entity, Boolean includ // 已进入待处理队列的,不再处理 if (stack.Contains(childs[i])) continue; - stack.Push(childs[i]); + if (depth < 0 || childs[i].Deepth <= depth) stack.Push(childs[i]); } } //// 去掉第一个,那是自身