树状结构的部分查询

表结构是

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

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

posted @ 2020-04-12 21:05  Lulus  阅读(733)  评论(0编辑  收藏  举报