Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support sorting tree node #15

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 81 additions & 23 deletions Abp.GeneralTree/GeneralTree/GeneralTreeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class GeneralTreeManager<TTree, TPrimaryKey> : IGeneralTreeManager<TTree,
private readonly IGeneralTreeConfiguration<TTree, TPrimaryKey> _generalTreeConfiguration;
private readonly IRepository<TTree, TPrimaryKey> _generalTreeRepository;

public IUnitOfWorkManager UnitOfWorkManager { get; set; }

public GeneralTreeManager(IGeneralTreeCodeGenerate generalTreeCodeGenerate,
IRepository<TTree, TPrimaryKey> generalTreeRepository,
IGeneralTreeConfiguration<TTree, TPrimaryKey> generalTreeConfiguration)
Expand Down Expand Up @@ -100,40 +102,96 @@ public virtual async Task UpdateAsync(TTree tree, Action<TTree> childrenAction =
}

[UnitOfWork]
public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action<TTree> childrenAction = null)
public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action<TTree> 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);
}
}

await UnitOfWorkManager.Current.SaveChangesAsync();//Must commit...

//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<string, TTree> updateDic = new Dictionary<string, TTree>();

//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]
Expand Down
103 changes: 80 additions & 23 deletions Abp.GeneralTree/GeneralTree/GeneralTreeManagerWithReferenceType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class
private readonly IGeneralTreeConfigurationWithReferenceType<TTree, TPrimaryKey> _generalTreeConfiguration;
private readonly IRepository<TTree, TPrimaryKey> _generalTreeRepository;

public IUnitOfWorkManager UnitOfWorkManager { get; set; }

public GeneralTreeManagerWithReferenceType(IGeneralTreeCodeGenerate generalTreeCodeGenerate,
IRepository<TTree, TPrimaryKey> generalTreeRepository,
IGeneralTreeConfigurationWithReferenceType<TTree, TPrimaryKey> generalTreeConfiguration)
Expand Down Expand Up @@ -101,39 +103,94 @@ public virtual async Task UpdateAsync(TTree tree, Action<TTree> childrenAction =
}

[UnitOfWork]
public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action<TTree> childrenAction = null)
public virtual async Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action<TTree> 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);
}
}

await UnitOfWorkManager.Current.SaveChangesAsync();//Must commit...

//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<string, TTree> updateDic = new Dictionary<string, TTree>();

//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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion Abp.GeneralTree/GeneralTree/IGeneralTreeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public interface IGeneralTreeManager<TTree, TPrimaryKey>

Task UpdateAsync(TTree tree, Action<TTree> childrenAction = null);

Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action<TTree> childrenAction = null);
Task MoveAsync(TPrimaryKey id, TPrimaryKey? parentId, Action<TTree> childrenAction = null, int? index = null);

Task DeleteAsync(TPrimaryKey id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public interface IGeneralTreeManagerWithReferenceType<TTree, in TPrimaryKey>

Task UpdateAsync(TTree tree, Action<TTree> childrenAction = null);

Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action<TTree> childrenAction = null);
Task MoveAsync(TPrimaryKey id, TPrimaryKey parentId, Action<TTree> childrenAction = null, int? index = null);

Task DeleteAsync(TPrimaryKey id);
}
Expand Down
73 changes: 73 additions & 0 deletions TreeTests/GeneralTreeManagerWithReferenceType_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
Loading