樹狀結構的部分查詢


表結構是

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

感覺會有更好的解,如果有思路的話,可以留言給我哦


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM