表结构是
- 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;
- }
示例代码
QueryTree
感觉会有更好的解, 如果有思路的话, 可以留言给我哦
来源: http://www.bubuko.com/infodetail-3504702.html