表結構是
public class RegionTree
{
/// <summary>
/// 自增長id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 自身的編碼,不同層級依次添加編碼
/// eg.湖北省為42,武漢市為4201,漢陽區為420105
/// </summary>
public string RegionCode { get; set; }
/// <summary>
/// 父級行政區編碼(記錄的是父級記錄的RegionId)
/// </summary>
public string RegionParentCode { get; set; }
/// <summary>
/// 行政區名稱
/// </summary>
public string Name {get; set; }
/// <summary>
/// 政區級別
/// </summary>
public AdministrativeLevelEnum AdministrativeLevel { get; set; }
}
業務要求並不是查詢所有行政區域的數據結構,而是根據登錄用戶所屬行政區域,返回其樹狀數據,即返回“部分”樹,並且一個用戶可能同時屬於不同的行政區域
比如,用戶屬於阜新市
、站前區
、西市區
、東光縣
、滄州高新技術產業開發區
,則返回的樹狀數據應該是
如圖所示,同一省的不同市、同一市的不同區,數據要合並到一顆樹上,這也是我感覺很繞的地方
返回的結果Dto RegionTreeNode
添加子節點集合
/// <summary>
/// 子節點
/// </summary>
public List<RegionTreeNode> Children { get; set; }
感覺查詢做的比較復雜,這里mark一下
public async Task TreeQuery()
{
//根據幾個節點id,查詢對應部分樹
var queryRegionIds = new List<string> { "130923", "210803", "130972", "1", "210802", "2109" };
var resultTree = new List<RegionTreeNode>();
var list = db.Regions.Where(x => queryRegionIds.Contains(x.RegionCode)).ToList();
//向上查詢
foreach (var d in list)
{
if (d.AdministrativeLevel != AdministrativeLevelEnum.Province)
{
var tree = await GetTree(d);
var isExistTree = resultTree.Find(x => x.Id == tree.Id);
//目前不存在此樹(此省級的數據)
if (isExistTree == null)
{
resultTree.Add(tree);
}
//存在此樹,需要將當前數據合並到現有樹的數據中
else
{
//查詢兩棵樹的交匯點
var intersectionId = GetIntersection(tree, isExistTree);
var resultTreeIntersection = GetIntersectionChild(isExistTree, intersectionId);
var treeIntersection = GetIntersectionChild(tree, intersectionId);
//將新樹的數據從交匯點開始,合並到現有樹
foreach (var child in treeIntersection.Children)
{
resultTreeIntersection.Children.Add(child);
}
}
}
else
{
var node = ConvertToTreeNode(d);
resultTree.Add(node);
}
}
//打斷點查看結果:resultTree
}
private async Task<RegionTreeNode> GetTree(RegionTree d)
{
RegionTreeNode tree = new RegionTreeNode();
List<RegionTree> list = new List<RegionTree>();
//向上查詢樹
var parent = await db.Regions.FirstOrDefaultAsync(x => x.RegionCode == d.RegionParentCode);
list.Add(d);
if (parent != null)
{
list.Add(parent);
}
int count = 0; //防止死循環
while (parent != null && count < 5)
{
parent = await db.Regions.FirstOrDefaultAsync(x => x.RegionCode == parent.RegionParentCode);
if (parent != null)
{
list.Add(parent);
}
count++;
}
//處理成樹結構
tree = ConvertToTreeNode(list[list.Count - 1]);
tree.Children = new List<RegionTreeNode>();
var node = tree.Children;
for (int i = list.Count - 2; i >= 0; i--)
{
var t = ConvertToTreeNode(list[i]);
node.Add(t);
node[0].Children = new List<RegionTreeNode>();
node = node[0].Children;
}
return tree;
}
private RegionTreeNode ConvertToTreeNode(RegionTree regionTree)
{
//這里可以寫成automap,懶得寫了~
return new RegionTreeNode()
{
Id = regionTree.Id,
RegionCode = regionTree.RegionCode,
RegionParentCode = regionTree.RegionParentCode,
AdministrativeLevel = regionTree.AdministrativeLevel,
Name = regionTree.Name,
Children=new List<RegionTreeNode>()
};
}
/// <summary>
/// 查詢兩棵樹的交匯點(最低的子節點)
/// </summary>
/// <param name="tree"></param>
/// <param name="isExistTree"></param>
/// <returns></returns>
private long GetIntersection(RegionTreeNode tree, RegionTreeNode isExistTree)
{
var treeCodeList = new List<RegionTreeNode>();
treeCodeList.Add(new RegionTreeNode() { Id = tree.Id, RegionCode = tree.RegionCode });
GetCodeList(tree, treeCodeList);
var isExistTreeCodeList = new List<RegionTreeNode>();
isExistTreeCodeList.Add(new RegionTreeNode() { Id = isExistTree.Id, RegionCode = isExistTree.RegionCode });
GetCodeList(isExistTree, isExistTreeCodeList);
//查詢重復的,最大的code
var intersectCodeList = (from t in treeCodeList
from i in isExistTreeCodeList
where t.Id == i.Id
select t).ToList();
var target = new RegionTreeNode() { RegionCode = "" };
foreach (var code in intersectCodeList)
{
//不同層級依次添加編碼
//eg.湖北省為42,武漢市為4201,漢陽區為420105
//這里尋找子節點
if (target.RegionCode.Length < code.RegionCode.Length)
{
target = code;
}
}
return target.Id;
}
private void GetCodeList(RegionTreeNode tree, List<RegionTreeNode> codeList)
{
foreach (var node in tree.Children)
{
codeList.Add(new RegionTreeNode() { Id = node.Id, RegionCode = node.RegionCode });
GetCodeList(node, codeList);
}
}
/// <summary>
/// 查詢交匯點節點
/// </summary>
/// <param name="intersection"></param>
/// <returns></returns>
private RegionTreeNode GetIntersectionChild(RegionTreeNode tree, long intersection)
{
if (tree.Id == intersection)
{
return tree;
}
//保證節點遍歷完
foreach (var node in tree.Children)
{
if (node.Id == intersection)
{
return node;
}
}
foreach (var node in tree.Children)
{
return GetIntersectionChild(node, intersection);
}
return null;
}
示例代碼
感覺會有更好的解,如果有思路的話,可以留言給我哦