/// <summary> /// 生成新的全名,以参考节点的全名作为基础 /// </summary> /// <param name="arg1"></param> /// <param name="arg2"></param> /// <param name="position"></param> /// <returns></returns> private string GenerateFullName(EntityTreeUpfydatingArgument arg1, EntityTreeUpfydatingArgument arg2, EntityTreePosition position) { var fullName = string.Empty; if (metaTree.Name == null || metaTree.FullName == null) { return(null); } //没有参考节点,则使用名称 if (arg2 == null) { fullName = arg1.NewValue.Name; } else { //获得参考节点的全名 fullName = arg2.NewValue.FullName; if (position != EntityTreePosition.Children) { //取前面一级的全名 fullName = GetPreviousFullName(fullName); } //拼接上当前的名称 fullName = string.Format("{0}{1}{2}", fullName, metaTree.NameSeparator, arg1.NewValue.Name); } return(fullName); }
/// <summary> /// 使用 <see cref="EntityTreeUpfydatingArgument"/> 更新实体属性。 /// </summary> /// <param name="entity"></param> /// <param name="argument"></param> /// <param name="force">是否强制修改。</param> private void UpdateEntityByArgument(IEntity entity, EntityTreeUpfydatingArgument argument, bool force = false) { //force强制修改属性 if (force || argument.OldValue.InnerId != argument.NewValue.InnerId) { entity.SetValue(metaTree.InnerSign, argument.NewValue.InnerId); } if (metaTree.Level != null && (force || argument.OldValue.Level != argument.NewValue.Level)) { entity.SetValue(metaTree.Level, argument.NewValue.Level); } if (metaTree.Order != null && (force || argument.OldValue.Order != argument.NewValue.Order)) { entity.SetValue(metaTree.Order, argument.NewValue.Order); } if (metaTree.Name != null && (force || argument.OldValue.Name != argument.NewValue.Name)) { entity.SetValue(metaTree.Name, argument.NewValue.Name); } if (metaTree.FullName != null && (force || argument.OldValue.FullName != argument.NewValue.FullName)) { entity.SetValue(metaTree.FullName, argument.NewValue.FullName); } }
/// <summary> /// 获取孩子、孙子、重孙...。 /// </summary> /// <param name="argument"></param> /// <param name="isolation"></param> /// <returns></returns> private IEnumerable <TEntity> GetChildren(EntityTreeUpfydatingArgument argument, Expression <Func <TEntity> > isolation = null) { var expression = TreeExpressionBuilder.BuildGetChildrenExpression <TEntity>(metaTree, argument.OldValue.InnerId); var querable = QueryHelper.CreateQuery <TEntity>(repository.Provider, expression); expression = TreeExpressionBuilder.AddIsolationExpression <TEntity>(querable.Expression, isolation); expression = TreeExpressionBuilder.AddUseableSelectExpression <TEntity>(metaTree, expression); return(repository.Provider.CreateQuery <TEntity>(expression).ToList()); }
private void UpdateChildren(TEntity current, IEnumerable <TEntity> entities, EntityTreeUpfydatingArgument argument) { foreach (var entity in entities) { var arg = CreateUpdatingArgument(entity); arg.NewValue.Level = argument.NewValue.Level + arg.OldValue.Level - argument.OldValue.Level; arg.NewValue.InnerId = argument.NewValue.InnerId + arg.OldValue.InnerId.Substring(argument.OldValue.Level * metaTree.SignLength); if (metaTree.FullName != null && !string.IsNullOrEmpty(argument.NewValue.FullName)) { arg.NewValue.FullName = argument.NewValue.FullName + metaTree.NameSeparator + GetRightFullName(arg.OldValue.FullName, argument.OldValue.Level); } UpdateEntityByArgument(entity, arg); } }
/// <summary> /// 将子节点移动到另一个子节点的下面。 /// </summary> /// <param name="current"></param> /// <param name="referEntity"></param> /// <param name="arg1"></param> /// <param name="arg2"></param> /// <param name="isolation"></param> private void UpdateMoveAsChildren(TEntity current, TEntity referEntity, EntityTreeUpfydatingArgument arg1, EntityTreeUpfydatingArgument arg2, Expression <Func <TEntity> > isolation = null) { //获取要移动节点的兄弟及其孩子 var brothers = GetBrothersAndChildren(arg1, false, null, isolation: isolation); //获取要移动的节点的孩子 var children = GetChildren(arg1, isolation); //兄弟及其孩子要下移一个单位 UpdateBrothersAndChildren(current, brothers, arg1.OldValue.InnerId, -1); //获得新节点的Order值 arg1.NewValue.Order = GetNewOrderNumber(arg2.OldValue, EntityTreePosition.Children, isolation: isolation); var modify = IsInList(referEntity, brothers); if (modify != null) { arg2 = CreateUpdatingArgument(modify); } var keyId = arg2.OldValue.InnerId; //获得参照节点的级别 arg1.NewValue.Level = arg2.OldValue.Level + 1; //生成新的InnerID arg1.NewValue.InnerId = GenerateInnerId(keyId, arg1.NewValue.Order, EntityTreePosition.Children); arg1.NewValue.FullName = GenerateFullName(arg1, arg2, EntityTreePosition.Children); //更新要移动的节点的孩子 UpdateChildren(current, children, arg1); UpdateEntityByArgument(current, arg1); SetNameNotModified(new[] { current }); SetNameNotModified(brothers); SetNameNotModified(children); repository.Update(current); repository.Batch(brothers, (u, s) => u.Update(s)); repository.Batch(children, (u, s) => u.Update(s)); }
/// <summary> /// 节点移动到根目录下,相关节点的更新。 /// </summary> /// <param name="current"></param> /// <param name="arg"></param> /// <param name="isolation"></param> /// <param name="cancellationToken">取消操作的通知。</param> private async Task UpdateMoveToRootAsync(TEntity current, EntityTreeUpfydatingArgument arg, Expression <Func <TEntity> > isolation = null, CancellationToken cancellationToken = default) { //获得新节点的Order值 var newOrder = GetNewOrderNumber(null, EntityTreePosition.Children, isolation: isolation); //获取它的兄弟及其孩子 var brothers = GetBrothersAndChildren(arg, false, null, isolation: isolation); //获取它的孩子 var children = GetChildren(arg, isolation); //生成新的InnerID var currentInnerId = GenerateInnerId(string.Empty, newOrder, EntityTreePosition.Children); //全名即为名称 if (metaTree.FullName != null && metaTree.Name != null) { arg.NewValue.FullName = arg.OldValue.Name; } arg.NewValue.InnerId = currentInnerId; arg.NewValue.Level = 1; arg.NewValue.Order = newOrder; UpdateEntityByArgument(current, arg); //兄弟及其孩子要上移一个单位 UpdateBrothersAndChildren(current, brothers, string.Empty, -1); //它的孩子要移到根节点下 UpdateChildren(current, children, arg); SetNameNotModified(new[] { current }); SetNameNotModified(brothers); SetNameNotModified(children); await repository.UpdateAsync(current); await repository.BatchAsync(brothers, (u, s) => u.Update(s)); await repository.BatchAsync(children, (u, s) => u.Update(s)); }
/// <summary> /// 节点移动到根目录下,相关节点的更新。 /// </summary> /// <param name="current"></param> /// <param name="arg"></param> /// <param name="isolation"></param> private void UpdateMoveToRoot(TEntity current, EntityTreeUpfydatingArgument arg, Expression <Func <TEntity> > isolation = null) { //获得新节点的Order值 var newOrder = GetNewOrderNumber(null, EntityTreePosition.Children, isolation: isolation); //获取它的兄弟及其孩子 var brothers = GetBrothersAndChildren(arg, false, null, isolation: isolation); //获取它的孩子 var children = GetChildren(arg, isolation); //生成新的InnerID var currentInnerId = GenerateInnerId(string.Empty, newOrder, EntityTreePosition.Children); //全名即为名称 if (metaTree.FullName != null && metaTree.Name != null) { arg.NewValue.FullName = arg.OldValue.Name; } arg.NewValue.InnerId = currentInnerId; arg.NewValue.Level = 1; arg.NewValue.Order = newOrder; UpdateEntityByArgument(current, arg); //兄弟及其孩子要上移一个单位 UpdateBrothersAndChildren(current, brothers, currentInnerId, -1); //它的孩子要移到根节点下 UpdateChildren(current, children, arg); repository.Update(current); repository.Batch(brothers, (u, s) => u.Update(s)); repository.Batch(children, (u, s) => u.Update(s)); }
/// <summary> /// 获取兄弟及他们的孩子。 /// </summary> /// <param name="argument"></param> /// <param name="includeCurrent">是否包含当 <paramref name="argument"/>,当在它前面插入时,需要包含它。</param> /// <param name="excludeArg">要排除的实体。</param> /// <param name="isTop">是否遇到要排除的实体就终止。</param> /// <param name="isolation"></param> /// <returns></returns> private IEnumerable <TEntity> GetBrothersAndChildren(EntityTreeUpfydatingArgument argument, bool includeCurrent, EntityTreeUpfydatingArgument excludeArg, bool isTop = false, Expression <Func <TEntity> > isolation = null) { var keyId = argument.OldValue.InnerId; var order = argument.OldValue.Order; var level = argument.OldValue.Level; var parameters = new ParameterCollection(); var m = EntityMetadataUnity.GetEntityMetadata(entityType); var sb = new StringBuilder(); sb.Append("SELECT "); var assert = new AssertFlag(); foreach (var property in GetUseableProperties()) { if (property == null) { continue; } if (!assert.AssertTrue()) { sb.Append(", "); } sb.AppendFormat("t.{0} {0}", QuoteColumn(property)); } sb.AppendFormat(" FROM {0} t", GetTableName()); sb.AppendFormat(" JOIN (SELECT f.{0} {0} FROM {1} f", QuoteColumn(metaTree.InnerSign), GetTableName()); sb.AppendFormat(" WHERE {0} LIKE {1} AND {5} = {6} AND {2} {4} {3}", QuoteColumn(metaTree.InnerSign), syntax.FormatParameter("pn"), GetOrderExpression(), order, includeCurrent ? ">=" : ">", GetLevelExpression(), level); if (m.DeleteProperty != null) { sb.AppendFormat(" AND {0} = {1}", QuoteColumn(m.DeleteProperty), 0); } if (excludeArg != null) { var excludeId = excludeArg.OldValue.InnerId; sb.AppendFormat(" AND NOT ({0} LIKE {1})", QuoteColumn(metaTree.InnerSign), syntax.FormatParameter("px")); parameters.Add("px", excludeId + "%"); if (isTop) { sb.AppendFormat(" AND {0} < {1}", QuoteColumn(metaTree.InnerSign), syntax.FormatParameter("px1")); parameters.Add("px1", excludeId); } } if (!includeCurrent) { sb.AppendFormat(" AND {0} <> {1}", QuoteColumn(metaTree.InnerSign), syntax.FormatParameter("pm")); parameters.Add("pm", keyId); } var conIsolation = string.Empty; if (isolation != null) { conIsolation = IsolationConditionBuilder.Build(isolation); if (!string.IsNullOrEmpty(conIsolation)) { sb.AppendFormat(" AND {0}", conIsolation); } } sb.AppendFormat(") f ON t.{0} LIKE {1}", QuoteColumn(metaTree.InnerSign), syntax.String.Concat("f." + QuoteColumn(metaTree.InnerSign), "'%'")); if (!string.IsNullOrEmpty(conIsolation)) { sb.AppendFormat(" WHERE {0}", conIsolation); } sb.AppendFormat("ORDER BY {0}", QuoteColumn(metaTree.InnerSign)); keyId = GetPreviousKey(keyId) + "_%"; parameters.Add("pn", keyId); return(database.ExecuteEnumerable((SqlCommand)sb.ToString(), parameters: parameters, rowMapper: new EntityRowMapper <TEntity>()).ToList()); }
/// <summary> /// 构造获取兄弟节点及孩子的表达式。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="metadata"></param> /// <param name="argument"></param> /// <param name="includeCurrent"></param> /// <param name="excludeArg"></param> /// <param name="isTop"></param> /// <returns></returns> internal static Expression BuildGetBrothersAndChildrenExpression <T>(EntityTreeMetadata metadata, EntityTreeUpfydatingArgument argument, bool includeCurrent, EntityTreeUpfydatingArgument excludeArg, bool isTop = false) { var parExp = Expression.Parameter(typeof(T), "s"); var memberExp = Expression.MakeMemberAccess(parExp, metadata.InnerSign.Info.ReflectionInfo); return(null); }