zoukankan      html  css  js  c++  java
  • 树状结构的部分查询

    表结构是

    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

    感觉会有更好的解,如果有思路的话,可以留言给我哦

  • 相关阅读:
    【GoLand】分享项目到Github平台
    【Git】实用教程
    【Go】Mac系统下安装GoLand 及 环境配置
    CF 901C Bipartite Segments
    CF 811E Vladik and Entertaining Flags
    Luogu P6300 悔改
    Luogu P3943 星空
    CSP2020 | T4
    NOIP2017 | D2T3
    Luogu P6852 Mex
  • 原文地址:https://www.cnblogs.com/Lulus/p/12687631.html
Copyright © 2011-2022 走看看