【发布时间】:2012-02-08 07:36:07
【问题描述】:
您将如何读取 SQL 数据以获取单位的分层列表?
不依赖于仅 SQL Server 的解决方案?
public class Unit {
public Unit Parent { get; set; }
public int Id { get; set; }
public String Name { get; set; }
}
List<Unit> list = new List<Unit>();
while(reader.Read())
{
// read sql data into clr object UNIT
}
表格有 3 列:
Id| ParentId | Name
1 | Null | bla
2 | 1 | x
3 | 1 | y
4 | 2 | z
5 | 2 | test
更新:
That is the code which is taken from user marc_s:
List<Unit> units = new List<Unit>();
String commandText =
@";WITH Hierarchy AS
(
SELECT
ID, ParentID = CAST(NULL AS INT),
Name, HierLevel = 1
FROM
dbo.Unit
WHERE
ParentID IS NULL
UNION ALL
SELECT
ht.ID, ht.ParentID, ht.Name, h1.HierLevel + 1
FROM
dbo.Unit ht
INNER JOIN
Hierarchy h1 ON ht.ParentID = h1.ID
)
SELECT Id, ParentId, Name
FROM Hierarchy
ORDER BY HierLevel, Id";
using(SqlConnection con = new SqlConnection(_connectionString))
using (SqlCommand cmd = new SqlCommand(commandText, con))
{
con.Open();
// use SqlDataReader to iterate over results
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
// get the info from the reader into the "Unit" object
Unit thisUnit = new Unit();
thisUnit.Id = Convert.ToInt32(rdr["Id"]);
thisUnit.UnitName = rdr["Name"].ToString();
// check if we have a parent
if (rdr["ParentId"] != DBNull.Value)
{
// get ParentId
int parentId = Convert.ToInt32(rdr["ParentId"]);
// find parent in list of units already loaded
// NOTE => not needed anymore => Unit parent = units.FirstOrDefault(u => u.Id == parentId);
// Instead use this method to find the parent:
Unit parent = FindParentUnit(units, parentId);
// if parent found - set this unit's parent to that object
if (parent != null)
{
thisUnit.Parent = parent;
parent.Children.Add(thisUnit);
}
}
else
{
units.Add(thisUnit);
}
}
}
}
return units;
这是填充列表的屏幕截图
http://oi41.tinypic.com/rmpe8n.jpg
这是 Unit 表中的 sql 数据:
http://oi40.tinypic.com/mt12sh.jpg
问题:
实际上填充的列表应该只有一个单元对象而不是 11(索引 0 - 10)。是的,列表中的第一个单元已正确填充,但索引 1 - 10 的单元不应出现在列表中。
实际上应该是这样的:
0
|--1
| |--3
| | |--9
| | |--10
| |--4
|--2
| |--5
| |--6
|--7
|--8
更新和解决方案
private static Unit FindParentUnit(List<Unit> units, int parentId)
{
Unit parent;
foreach (Unit u in units)
{
if (u.Id == parentId){
return u;
}
parent = FindParentUnit(u.Children, parentId);
if (parent != null)
return parent;
}
return null;
}
【问题讨论】:
-
参见Wikipedia ON CTE:DB2、Firebird [1]、Microsoft SQL Server、Oracle、PostgreSQL、HyperSQL 和 H2 支持公共表表达式(实验性)
-
好的 - 那么问题是什么?您的“根”人 (ID=0) 有 四个孩子 - 正如您提供的数据所预期的那样。我敢肯定,如果您深入了解该根人员的“子项”集合,您也会找到其他节点及其子节点。
-
如果您不想将所有节点都放入列表中 - 就不要这样做! :-) 所以在
if (rdr["ParentId"] != DBNull.Value)之后,有一个else { .... }子句并将语句units.Add(thisUnit);放入那个else 子句 - 然后只有那些没有父单元的单元将被卡在列表中。 ..相应地更新了我的答案..... -
单位父=units.FirstOrDefault(u => u.Id == parentId); Id 3 或 Id 4 的父级是 ParentId 1,它不在根级别的单位列表中,而是在 ID 为 1 的单位的 children 属性中。可能是 Linq SelectMany 帮助这不会是高性能的......是的,你的列表有 11 个单元对象的原始版本应该与 units.FirstOrDefault 搜索一起使用,但我只想要列表中的一个单元,因为它的层次结构绑定到一个控件,看到所有单元看起来很傻......