65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 HierarchyID 加载 TreeView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (9投票s)

2009年6月5日

CPOL

3分钟阅读

viewsIcon

120331

downloadIcon

5168

使用 SQL Server 2008 Hierarchy ID 数据类型填充 TreeView

Tree.jpg

引言

本文演示了如何基于 SQL Server 2008 中的新 hierarchyID 数据类型加载 TreeView。我以前加载 TreeView 的方法要么是使用具有数据关系的数据集,要么是使用具有父/子层次结构的数据表。

我发现您需要限制 TreeView 中的节点数量才能保持加载性能。使用 hierarchyid,这个限制得到了提高。我对加载速度感到惊喜。

本文假设您已使用 SQL 2008 中的 hierarchyID 构建了结果集。该示例表以 XML 形式存储,具有现实的大小和复杂性,因为它基于经过清理的实际数据。构建结果集本身就是一个挑战,而且过于个性化,在此不予涵盖。

背景 

MSDN 包含一些非常有用的示例和教程。

Using the Code

首先,您需要引用 Microsoft 类型,因为 hierarchyid 不是您所期望的 SQLDBType

using Microsoft.SqlServer.Types; 

获取数据

再次,我将数据类拆分出来,并为此演示使用了 XML 示例数据文件。请注意,从文本系统加载数据时,hierarchyID 需要在 ID 有用之前从文本中进行转换。

//convert the string back into a hierarchyid
oRow["NodeKey"] = SqlHierarchyId.Parse((string)oRow["NodeString"]);

我将此数据加载到 datagridview 中,以便在加载 TreeView 之前检查内容。请注意 hierarchyID 的结构,它是用正斜杠分隔的 ID 值。

Grid.jpg

这里有一条关于在 SQL Server 中构建 hierarchyID 的说明,所有 Microsoft 的教程都使用 ID 号来指定层次结构级别内节点的顺序。这带来了问题,因为我需要从 UI 添加节点,而重复节点自然是不允许的,所以我必须在 UI 中构建节点时对 ID 进行一些处理。

我的解决方法是使用数据库中的 ID。我在 select 语句中使用顺序来排序显示,并且我没有要求在层次结构内的级别中排序数据。这也可以通过 LINQ 过滤器来实现,但我更熟悉 TSQL。

加载 TreeView

自然,hierachyID 函数不能在 dataview 过滤器或 datatable select 中使用,函数支持有限。所以,我需要找到另一种方法来识别父/子节点以加载到 TreeView 中。我看了看使用 NodeString 字段和 string.contains 以及计算分隔符的数量(这也有效)。

似乎微软在 SQL Server 中实现了 hierarchyid 却没有在 CLR 中实现,这似乎不对,毕竟您应该能够集成两者。所以,又花了几小时的搜索,找到了对 SQLTypes 的引用,从那里转向 LINQ 是显而易见的。

我将 LoadTreeSQLHierarchyLoadNodeSQLHierarchy 构建成可以移动到实用类中的方式。

private void LoadTreeSQLHierarchy(TreeView oTV, DataTable oTable, 
		string sKeyField, string sTextField)
{
	oTV.Nodes.Clear();

	TreeNode oNode;

	//get an empty id to get the top node
	SqlHierarchyId iID = new SqlHierarchyId();

	//filter the table using linq. See blog for equals()/== issue
	EnumerableRowCollection<DataRow> query = 
		from TNodes in oTable.AsEnumerable()
		where TNodes.Field<SqlHierarchyId>
			(sKeyField).GetAncestor(1).Equals(iID)
		select TNodes;

	//convert to a dataview because I am comfortable with a dataview.
	DataView oDV = query.AsDataView();
	if (oDV.Count == 1)
	{
		//load up a node
		oNode = new TreeNode(oDV[0][sTextField].ToString());

		//put the datarow into the tag property
		oNode.Tag = oDV[0].Row;

		//load up the children
		LoadNodeSQLHierarchy(oNode, oTable);

		//add the node hierarchy to the tree
		oTV.Nodes.Add(oNode);
	}
} 

通过使用空的 hierarchyID 和初始 LINQ 查询中的 GetAncestor(1),我们检索了顶级节点。这允许我们使用一种方法来加载树和节点,但我们需要处理 TreeViewTreeNode 的不同类型。我认为使用两种方法更简单。

我从 这里 获得了 .Equals() 的要求。

由于我对数据结构更熟悉,我使用 DataView 来填充 treeview 的顶级节点。一旦有了顶级节点,我就可以递归调用 LoadNodeSQLHierarchy 来填充整个结构。

使用 dataview 的另一个好处是,我可以将 datarow 放入节点的 tag 属性中,并在 UI 中处理树时可以使用它。

兴趣点 

我非常不喜欢 hierarchyID 的地方在于它不是 SQLDBType,因此打破了我基于存储过程和 SQLDBTypes 的 ORM 层。

历史 

  • 第一个版本
© . All rights reserved.