From 8d9ef864b8159c3c0c23038599c491d0572266ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=8E=E5=8E=9F=E5=B0=8F=E7=89=9B?= Date: Wed, 5 Jun 2019 09:56:43 +0800 Subject: [PATCH 1/2] sort feature --- .../GeneralTree/GeneralTreeManager.cs | 100 ++++++++++++++---- .../GeneralTreeManagerWithReferenceType.cs | 99 +++++++++++++---- .../GeneralTree/IGeneralTreeManager.cs | 2 +- .../IGeneralTreeManagerWithReferenceType.cs | 2 +- ...neralTreeManagerWithReferenceType_Tests.cs | 73 +++++++++++++ TreeTests/GeneralTreeManager_Tests.cs | 95 ++++++++++++++++- 6 files changed, 320 insertions(+), 51 deletions(-) diff --git a/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs b/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs index 9641786..34b50b3 100644 --- a/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs +++ b/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs @@ -100,40 +100,94 @@ public virtual async Task UpdateAsync(TTree tree, Action childrenAction = } [UnitOfWork] - public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action childrenAction = null) + public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action childrenAction = null, int? index = null) { var tree = await _generalTreeRepository.GetAsync(id); - if (tree.ParentId.Equals(parentId)) + + if (!tree.ParentId.Equals(parentId))//Move level { - return; - } + //Should find children before Code change + var children = await GetChildrenAsync(id, true); - //Should find children before Code change - var children = await GetChildrenAsync(id, true); + //Store old code and full name of Tree + var oldCode = tree.Code; + var oldFullName = tree.FullName; - //Store old code and full name of Tree - var oldCode = tree.Code; - var oldFullName = tree.FullName; + //Move Tree - //Move Tree - tree.Code = await GetNextChildCodeAsync(parentId); - tree.Level = tree.Code.Split('.').Length; - tree.ParentId = parentId; - tree.FullName = await GetChildFullNameAsync(parentId, tree.Name); - CheckSameName(tree); + tree.Code = await GetNextChildCodeAsync(parentId); + tree.Level = tree.Code.Split('.').Length; + tree.ParentId = parentId; + tree.FullName = await GetChildFullNameAsync(parentId, tree.Name); - //Update Children Codes and FullName - foreach (var child in children) + CheckSameName(tree); + + //Update Children Codes and FullName + foreach (var child in children) + { + child.Code = _generalTreeCodeGenerate.MergeCode(tree.Code, + _generalTreeCodeGenerate.RemoveParentCode(child.Code, oldCode)); + child.FullName = _generalTreeCodeGenerate.MergeFullName(tree.FullName, + _generalTreeCodeGenerate.RemoveParentCode(child.FullName, oldFullName));//RemoveParentCode just sub string + child.Level = child.Code.Split('.').Length; + + childrenAction?.Invoke(child); + } + } + + //Move index + if (index.HasValue) { - child.Code = _generalTreeCodeGenerate.MergeCode(tree.Code, - _generalTreeCodeGenerate.RemoveParentCode(child.Code, oldCode)); - child.FullName = _generalTreeCodeGenerate.MergeFullName(tree.FullName, - _generalTreeCodeGenerate.RemoveParentCode(child.FullName, oldFullName)); - child.Level = child.Code.Split('.').Length; + if (index.Value < 0) + { + throw new ArgumentOutOfRangeException($"{nameof(index)} cannot be less than 0."); + } + + //Store the code update info + Dictionary updateDic = new Dictionary(); + + //Update all the same level + var sameLevelNodes = await GetChildrenAsync(parentId, false);// this incule 'tree' + sameLevelNodes = sameLevelNodes.OrderBy(m => m.Code).ToList(); + + if (index.Value > sameLevelNodes.Count - 1) + { + //Move to last + index = sameLevelNodes.Count - 1; + } + + sameLevelNodes.RemoveAll(m => m.Id.Equals(tree.Id)); + sameLevelNodes.Insert(index.Value, tree); + + var parentCode = _generalTreeCodeGenerate.GetParentCode(tree.Code); + var startCode = _generalTreeCodeGenerate.MergeCode(parentCode, + _generalTreeCodeGenerate.CreateCode(1)); + foreach (var sameLevel in sameLevelNodes) + { + if (sameLevel.Code != startCode)//Ignore index has not changed + { + updateDic[startCode] = sameLevel; + var levelChildren = await GetChildrenAsync(sameLevel.Id, true); + foreach (var levelChild in levelChildren) + { + var childCode = _generalTreeCodeGenerate.MergeCode(startCode, + _generalTreeCodeGenerate.RemoveParentCode(levelChild.Code, sameLevel.Code)); + updateDic[childCode] = levelChild; + } + } + + startCode = _generalTreeCodeGenerate.GetNextCode(startCode); + } + + //Do update + foreach (var up in updateDic) + { + up.Value.Code = up.Key; + } - childrenAction?.Invoke(child); } + } [UnitOfWork] diff --git a/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs b/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs index b5d963c..5bd59a8 100644 --- a/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs +++ b/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs @@ -101,39 +101,92 @@ public virtual async Task UpdateAsync(TTree tree, Action childrenAction = } [UnitOfWork] - public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action childrenAction = null) + public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action childrenAction = null, int? index = null) { var tree = await _generalTreeRepository.GetAsync(id); - if (tree.ParentId.Equals(parentId)) + + if (!tree.ParentId.Equals(parentId))//Move level { - return; - } + //Should find children before Code change + var children = await GetChildrenAsync(id, true); - //Should find children before Code change - var children = await GetChildrenAsync(id, true); + //Store old code and full name of Tree + var oldCode = tree.Code; + var oldFullName = tree.FullName; - //Store old code and full name of Tree - var oldCode = tree.Code; - var oldFullName = tree.FullName; + //Move Tree - //Move Tree - tree.Code = await GetNextChildCodeAsync(parentId); - tree.Level = tree.Code.Split('.').Length; - tree.ParentId = parentId; - tree.FullName = await GetChildFullNameAsync(parentId, tree.Name); - CheckSameName(tree); + tree.Code = await GetNextChildCodeAsync(parentId); + tree.Level = tree.Code.Split('.').Length; + tree.ParentId = parentId; + tree.FullName = await GetChildFullNameAsync(parentId, tree.Name); - //Update Children Codes and FullName - foreach (var child in children) + CheckSameName(tree); + + //Update Children Codes and FullName + foreach (var child in children) + { + child.Code = _generalTreeCodeGenerate.MergeCode(tree.Code, + _generalTreeCodeGenerate.RemoveParentCode(child.Code, oldCode)); + child.FullName = _generalTreeCodeGenerate.MergeFullName(tree.FullName, + _generalTreeCodeGenerate.RemoveParentCode(child.FullName, oldFullName));//RemoveParentCode just sub string + child.Level = child.Code.Split('.').Length; + + childrenAction?.Invoke(child); + } + } + + //Move index + if (index.HasValue) { - child.Code = _generalTreeCodeGenerate.MergeCode(tree.Code, - _generalTreeCodeGenerate.RemoveParentCode(child.Code, oldCode)); - child.FullName = _generalTreeCodeGenerate.MergeFullName(tree.FullName, - _generalTreeCodeGenerate.RemoveParentCode(child.FullName, oldFullName)); - child.Level = child.Code.Split('.').Length; + if (index.Value < 0) + { + throw new ArgumentOutOfRangeException($"{nameof(index)} cannot be less than 0."); + } + + //Store the code update info + Dictionary updateDic = new Dictionary(); + + //Update all the same level + var sameLevelNodes = await GetChildrenAsync(parentId, false);// this incule 'tree' + sameLevelNodes = sameLevelNodes.OrderBy(m => m.Code).ToList(); + + if (index.Value > sameLevelNodes.Count - 1) + { + //Move to last + index = sameLevelNodes.Count - 1; + } + + sameLevelNodes.RemoveAll(m => m.Id.Equals(tree.Id)); + sameLevelNodes.Insert(index.Value, tree); + + var parentCode = _generalTreeCodeGenerate.GetParentCode(tree.Code); + var startCode = _generalTreeCodeGenerate.MergeCode(parentCode, + _generalTreeCodeGenerate.CreateCode(1)); + foreach (var sameLevel in sameLevelNodes) + { + if (sameLevel.Code != startCode)//Ignore index has not changed + { + updateDic[startCode] = sameLevel; + var levelChildren = await GetChildrenAsync(sameLevel.Id, true); + foreach (var levelChild in levelChildren) + { + var childCode = _generalTreeCodeGenerate.MergeCode(startCode, + _generalTreeCodeGenerate.RemoveParentCode(levelChild.Code, sameLevel.Code)); + updateDic[childCode] = levelChild; + } + } + + startCode = _generalTreeCodeGenerate.GetNextCode(startCode); + } + + //Do update + foreach (var up in updateDic) + { + up.Value.Code = up.Key; + } - childrenAction?.Invoke(child); } } diff --git a/Abp.GeneralTree/GeneralTree/IGeneralTreeManager.cs b/Abp.GeneralTree/GeneralTree/IGeneralTreeManager.cs index a368777..25216f5 100644 --- a/Abp.GeneralTree/GeneralTree/IGeneralTreeManager.cs +++ b/Abp.GeneralTree/GeneralTree/IGeneralTreeManager.cs @@ -18,7 +18,7 @@ public interface IGeneralTreeManager Task UpdateAsync(TTree tree, Action childrenAction = null); - Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action childrenAction = null); + Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action childrenAction = null, int? index = null); Task DeleteAsync(TPrimaryKey id); } diff --git a/Abp.GeneralTree/GeneralTree/IGeneralTreeManagerWithReferenceType.cs b/Abp.GeneralTree/GeneralTree/IGeneralTreeManagerWithReferenceType.cs index 0876cc6..b5e2d3d 100644 --- a/Abp.GeneralTree/GeneralTree/IGeneralTreeManagerWithReferenceType.cs +++ b/Abp.GeneralTree/GeneralTree/IGeneralTreeManagerWithReferenceType.cs @@ -18,7 +18,7 @@ public interface IGeneralTreeManagerWithReferenceType Task UpdateAsync(TTree tree, Action childrenAction = null); - Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action childrenAction = null); + Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action childrenAction = null, int? index = null); Task DeleteAsync(TPrimaryKey id); } diff --git a/TreeTests/GeneralTreeManagerWithReferenceType_Tests.cs b/TreeTests/GeneralTreeManagerWithReferenceType_Tests.cs index b2084ec..6946e78 100644 --- a/TreeTests/GeneralTreeManagerWithReferenceType_Tests.cs +++ b/TreeTests/GeneralTreeManagerWithReferenceType_Tests.cs @@ -610,6 +610,79 @@ public async Task Move_Test() cd.Code.ShouldBe(_generalTreeCodeGenerate.GetNextCode(beijingLastChild.Code)); } + [Fact] + public async Task Move_Index_Test() + { + //Act + var beijing = await CreateRegion("beijing"); + var dongcheng = await CreateRegion("dongcheng", beijing.Id); + dongcheng.Code.ShouldBe("00001.00001"); + var xicheng = await CreateRegion("xicheng", beijing.Id); + xicheng.Code.ShouldBe("00001.00002"); + + var hebei = await CreateRegion("hebei"); + await CreateRegion("shijiazhuang", hebei.Id); + var chengde = await CreateRegion("chengde", hebei.Id); + chengde.Code.ShouldBe("00002.00002"); + + var shaungqiao = await CreateRegion("va", chengde.Id); + shaungqiao.Code.ShouldBe("00002.00002.00001"); + var shaungluan = await CreateRegion("shaungluan", chengde.Id); + shaungluan.Code.ShouldBe("00002.00002.00002"); + + var bazhong = await CreateRegion("bazhong", shaungluan.Id); + bazhong.Code.ShouldBe("00002.00002.00002.00001"); + + var beijingLastChild = GetRegion("xicheng"); + beijingLastChild.ShouldNotBeNull(); + await _generalRegion2TreeManager.MoveAsync(chengde.Id, beijing.Id, index: 0); + + //Assert + var cd = GetRegion(chengde.Name); + cd.ShouldNotBeNull(); + cd.FullName.ShouldBe(beijing.FullName + "-" + chengde.Name); + cd.ParentId.ShouldBe(beijing.Id); + cd.Level.ShouldBe(beijing.Level + 1); + cd.Code.ShouldBe("00001.00001"); + + shaungqiao = GetRegion(shaungqiao.Name); + shaungqiao.Code.ShouldBe("00001.00001.00001"); + + var dc = GetRegion(dongcheng.Name); + dc.Code.ShouldBe("00001.00002"); + + var xc = GetRegion(xicheng.Name); + xc.Code.ShouldBe("00001.00003"); + + //Move and check children + await _generalRegion2TreeManager.MoveAsync(shaungqiao.Id, beijing.Id, index: 0); + cd = GetRegion(chengde.Name); + cd.Code.ShouldBe("00001.00002"); + shaungqiao = GetRegion(shaungqiao.Name); + shaungqiao.Code.ShouldBe("00001.00001"); + + //Only change index + await _generalRegion2TreeManager.MoveAsync(chengde.Id, beijing.Id, index: 2);// Move cd from index 0 to index 2 + cd = GetRegion(chengde.Name); + cd.Code.ShouldBe("00001.00003"); + + shaungqiao = GetRegion(shaungqiao.Name); + shaungqiao.Code.ShouldBe("00001.00001"); + + dc = GetRegion(dongcheng.Name); + dc.Code.ShouldBe("00001.00002"); + + xc = GetRegion(xicheng.Name); + xc.Code.ShouldBe("00001.00004"); + + shaungluan = GetRegion(shaungluan.Name); + shaungluan.Code.ShouldBe("00001.00003.00002"); + + await _generalRegion2TreeManager.MoveAsync(chengde.Id, beijing.Id, index: 20);// Move cd to last + cd = GetRegion(chengde.Name); + cd.Code.ShouldBe("00001.00004"); + } + [Fact] public async Task Update_ChildrenAction_Test() { diff --git a/TreeTests/GeneralTreeManager_Tests.cs b/TreeTests/GeneralTreeManager_Tests.cs index b632fa9..59cd4bb 100644 --- a/TreeTests/GeneralTreeManager_Tests.cs +++ b/TreeTests/GeneralTreeManager_Tests.cs @@ -589,9 +589,15 @@ public async Task Move_Test() var hebei = await CreateRegion("hebei"); await CreateRegion("shijiazhuang", hebei.Id); var chengde = await CreateRegion("chengde", hebei.Id); + chengde.Code.ShouldBe("00002.00002"); - await CreateRegion("shaungqiao", chengde.Id); - await CreateRegion("shaungluan", chengde.Id); + var shaungqiao = await CreateRegion("va", chengde.Id); + shaungqiao.Code.ShouldBe("00002.00002.00001"); + var shaungluan = await CreateRegion("shaungluan", chengde.Id); + shaungluan.Code.ShouldBe("00002.00002.00002"); + + var bazhong = await CreateRegion("bazhong", shaungluan.Id); + bazhong.Code.ShouldBe("00002.00002.00002.00001"); var beijingLastChild = GetRegion("xicheng"); beijingLastChild.ShouldNotBeNull(); @@ -603,7 +609,90 @@ public async Task Move_Test() cd.FullName.ShouldBe(beijing.FullName + "-" + chengde.Name); cd.ParentId.ShouldBe(beijing.Id); cd.Level.ShouldBe(beijing.Level + 1); - cd.Code.ShouldBe(_generalTreeCodeGenerate.GetNextCode(beijingLastChild.Code)); + var cdCode = _generalTreeCodeGenerate.GetNextCode(beijingLastChild.Code);//00001.00003 + cd.Code.ShouldBe(cdCode); + + shaungqiao = GetRegion(shaungqiao.Name); + shaungqiao.Code.ShouldBe("00001.00003.00001"); + + shaungluan = GetRegion(shaungluan.Name); + shaungluan.Code.ShouldBe("00001.00003.00002"); + + bazhong = GetRegion(bazhong.Name); + bazhong.Code.ShouldBe("00001.00003.00002.00001"); + } + + [Fact] + public async Task Move_Index_Test() + { + //Act + var beijing = await CreateRegion("beijing"); + var dongcheng = await CreateRegion("dongcheng", beijing.Id); + dongcheng.Code.ShouldBe("00001.00001"); + var xicheng = await CreateRegion("xicheng", beijing.Id); + xicheng.Code.ShouldBe("00001.00002"); + + var hebei = await CreateRegion("hebei"); + await CreateRegion("shijiazhuang", hebei.Id); + var chengde = await CreateRegion("chengde", hebei.Id); + chengde.Code.ShouldBe("00002.00002"); + + var shaungqiao = await CreateRegion("va", chengde.Id); + shaungqiao.Code.ShouldBe("00002.00002.00001"); + var shaungluan = await CreateRegion("shaungluan", chengde.Id); + shaungluan.Code.ShouldBe("00002.00002.00002"); + + var bazhong = await CreateRegion("bazhong", shaungluan.Id); + bazhong.Code.ShouldBe("00002.00002.00002.00001"); + + var beijingLastChild = GetRegion("xicheng"); + beijingLastChild.ShouldNotBeNull(); + await _generalRegionTreeManager.MoveAsync(chengde.Id, beijing.Id, index: 0); + + //Assert + var cd = GetRegion(chengde.Name); + cd.ShouldNotBeNull(); + cd.FullName.ShouldBe(beijing.FullName + "-" + chengde.Name); + cd.ParentId.ShouldBe(beijing.Id); + cd.Level.ShouldBe(beijing.Level + 1); + cd.Code.ShouldBe("00001.00001"); + + shaungqiao = GetRegion(shaungqiao.Name); + shaungqiao.Code.ShouldBe("00001.00001.00001"); + + var dc = GetRegion(dongcheng.Name); + dc.Code.ShouldBe("00001.00002"); + + var xc = GetRegion(xicheng.Name); + xc.Code.ShouldBe("00001.00003"); + + //Move and check children + await _generalRegionTreeManager.MoveAsync(shaungqiao.Id, beijing.Id, index: 0); + cd = GetRegion(chengde.Name); + cd.Code.ShouldBe("00001.00002"); + shaungqiao = GetRegion(shaungqiao.Name); + shaungqiao.Code.ShouldBe("00001.00001"); + + //Only change index + await _generalRegionTreeManager.MoveAsync(chengde.Id, beijing.Id, index: 2);// Move cd from index 0 to index 2 + cd = GetRegion(chengde.Name); + cd.Code.ShouldBe("00001.00003"); + + shaungqiao = GetRegion(shaungqiao.Name); + shaungqiao.Code.ShouldBe("00001.00001"); + + dc = GetRegion(dongcheng.Name); + dc.Code.ShouldBe("00001.00002"); + + xc = GetRegion(xicheng.Name); + xc.Code.ShouldBe("00001.00004"); + + shaungluan = GetRegion(shaungluan.Name); + shaungluan.Code.ShouldBe("00001.00003.00002"); + + await _generalRegionTreeManager.MoveAsync(chengde.Id, beijing.Id, index: 20);// Move cd to last + cd = GetRegion(chengde.Name); + cd.Code.ShouldBe("00001.00004"); } [Fact] From f48b2f79b21bd676f0f85fc49fb1372eee7d95d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=8E=E5=8E=9F=E5=B0=8F=E7=89=9B?= Date: Mon, 10 Jun 2019 18:03:41 +0800 Subject: [PATCH 2/2] commit before index --- Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs | 4 ++++ .../GeneralTree/GeneralTreeManagerWithReferenceType.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs b/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs index 34b50b3..69a339f 100644 --- a/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs +++ b/Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs @@ -20,6 +20,8 @@ public class GeneralTreeManager : IGeneralTreeManager _generalTreeConfiguration; private readonly IRepository _generalTreeRepository; + public IUnitOfWorkManager UnitOfWorkManager { get; set; } + public GeneralTreeManager(IGeneralTreeCodeGenerate generalTreeCodeGenerate, IRepository generalTreeRepository, IGeneralTreeConfiguration generalTreeConfiguration) @@ -136,6 +138,8 @@ public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Actio } } + await UnitOfWorkManager.Current.SaveChangesAsync();//Must commit... + //Move index if (index.HasValue) { diff --git a/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs b/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs index 5bd59a8..4237b66 100644 --- a/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs +++ b/Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs @@ -21,6 +21,8 @@ public class private readonly IGeneralTreeConfigurationWithReferenceType _generalTreeConfiguration; private readonly IRepository _generalTreeRepository; + public IUnitOfWorkManager UnitOfWorkManager { get; set; } + public GeneralTreeManagerWithReferenceType(IGeneralTreeCodeGenerate generalTreeCodeGenerate, IRepository generalTreeRepository, IGeneralTreeConfigurationWithReferenceType generalTreeConfiguration) @@ -137,6 +139,8 @@ public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action } } + await UnitOfWorkManager.Current.SaveChangesAsync();//Must commit... + //Move index if (index.HasValue) {