将sql层次结构读取到c#对象中
本文关键字:对象 读取 sql 层次结构 | 更新日期: 2023-09-27 18:23:38
如何读取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
问题:
实际上,填充的List应该只有一个Unit对象,而不是11(索引0-10)。是的,列表中的第一个单元被正确填充,但索引1-10的单元不应该在列表中。
这就是实际情况:
0
|--1
| |--3
| | |--9
| | |--10
| |--4
|--2
| |--5
| |--6
|--7
|--8
更新和SOLUTiON
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;
}
实现这一点的一种方法是使用对象关系映射器,例如实体框架来为您完成工作。这个类似EF问题的答案应该为你指明正确的方向。
应该这样做:-)
// set up connection string
string connectionString = "server=.;database=test;integrated Security=SSPI;";
// define a CTE (Common Table Expression) to recursively build your hierarchical
// structure into a flat list and order it according to its "sequence" (root first)
string cteStatement =
@";WITH Hierarchy AS
(
SELECT
ID, ParentID = CAST(NULL AS INT),
Name, HierLevel = 1
FROM
dbo.HierarchyTest -- replace with your table name!
WHERE
ParentID IS NULL
UNION ALL
SELECT
ht.ID, ht.ParentID, ht.Name, h1.HierLevel + 1
FROM
dbo.HierarchyTest ht -- replace with your table name!
INNER JOIN
Hierarchy h1 ON ht.ParentID = h1.ID
)
SELECT Id, ParentId, Name
FROM Hierarchy
ORDER BY HierLevel, Id";
// set up list of "Unit" objects
List<Unit> units = new List<Unit>();
// create connection and command to query
using(SqlConnection conn = new SqlConnection(connectionString))
using(SqlCommand cmd = new SqlCommand(cteStatement, conn))
{
conn.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 = rdr.GetInt32(0);
thisUnit.Name = rdr.GetString(2);
thisUnit.Children = new List<Unit>();
// check if we have a parent
if(!rdr.IsDBNull(1))
{
// get ParentId
int parentId = rdr.GetInt32(1);
// find parent in list of units already loaded
Unit parent = units.FirstOrDefault(u => u.Id == 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);
}
}
}
conn.Close();
}
这对你有用吗??
CTE(Common Table Expression)递归地扫描您的表,并建立一个层次节点列表-通过按"层次级别"对其进行排序,您可以确保在其子节点出现之前获得所有父节点(以便代码工作)
更新:好的,所以你似乎想把只有节点,而没有父节点放入结果列表中-没关系(但你并没有真的说你想这样!!)-我更新了上面的代码-请再次检查!!
您的数据表示一个树结构,您只需要构建树来创建根单元并添加叶子。您可以在树中使用Dictionary而不是List进行搜索,这很简单。这里有一个仅在行按id:升序排列时有效的示例
Dictionary<Int32,Unit> dic = new Dictionary<Int32,Unit>();
while(reader.Read())
{
//create the new Unit
// if the parent is not null get the parent unit from dic
// add the new Unit to dic
}