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();
diff --git a/XCode/Tree/EntityTree.cs b/XCode/Tree/EntityTree.cs
index d31a17dfe..feb847ea7 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);
}
@@ -288,18 +288,19 @@ 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 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)
{
@@ -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]);
}
}
//// 去掉第一个,那是自身
@@ -337,7 +338,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 +364,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 +387,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 +414,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 +434,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 +503,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 +589,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 +653,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