如何从SQL读取父子数据?
再次感谢您发布的所有精彩答案!
我在 SQL 中有两个表。第一个定义父项,并有一个名为 ParentId 的主键列。我还有一个子表,它有一个主键和一个外键“ParentId”。因此,这两个表形成了单父-多子关系。
问题是拉取父+子数据C#代码最有效的方法是什么?数据必须读入以下对象:
public class Parent
{
public int ParentId { get; set; }
public List<Child> Children { get; set; }
// ... many more properties ... //
}
public class Child
{
public int ChildId { get; set; }
public string Description { get; set; }
// ... many more properties ... //
}
如果我使用以下查询,我将立即获取父级和子级,其中每个父级将重复其拥有的子级数:
SELECT
p.ParentId as 'ParentId',
c.ChildId as 'ChildId',
-- other relevant fields --
FROM
Parents p
INNER JOIN
Children c
ON
p.ParentId = c.ParentId
使用这种方法,我必须找到所有唯一的父行,然后读取所有子行。优点是我只访问数据库 1 次。
第二个版本是分别读取所有父项:
SELECT * FROM Parents
然后分别读取所有子项:
SELECT * FROM Children
并使用 LINQ 将所有父项与子项合并。这种方法会访问数据库 2 次。
第三种也是最后一种(也是最低效的)方法是获取所有父对象,并在构造每个父对象时,访问数据库以获取其所有子对象。此方法需要 n+1 个连接:1 个连接用于所有父级,n 次行程以获得每个父级的所有子级。
关于如何更轻松地做到这一点有什么建议吗?当然,我无法摆脱使用存储过程,并且我无法使用 LINQ2SQL 或 EF。您更喜欢数据表还是数据读取器?如果是,如何使用方法 1 或方法 2?
谢谢, 马丁
Thanks again for all the wonderful answers you have all posted!
I have two tables in SQL. The first defines the parent, and has a primary key column called ParentId. I also have a child table that has a primary key, and a foreign key as 'ParentId'. So the two tables form a one parent - to many children relationship.
The question is what is the most efficient way to pull the parent + child data C# code? The data has to be read into the following objects:
public class Parent
{
public int ParentId { get; set; }
public List<Child> Children { get; set; }
// ... many more properties ... //
}
public class Child
{
public int ChildId { get; set; }
public string Description { get; set; }
// ... many more properties ... //
}
If i use the following query I will get the parent and the children at once where each parent will be repeated as many times as many children it has:
SELECT
p.ParentId as 'ParentId',
c.ChildId as 'ChildId',
-- other relevant fields --
FROM
Parents p
INNER JOIN
Children c
ON
p.ParentId = c.ParentId
Using this approach I'd have to find all the unique parent rows, and then read all the children. The advantage is that I only make 1 trip to the db.
The second version of this is to read all parents separately:
SELECT * FROM Parents
and then read all children separately:
SELECT * FROM Children
and use LINQ to merge all parents with children. This approach makes 2 trips to the db.
The third and final (also most inefficient) approach is to grab all parents, and while constructing each parent object, make a trip to the DB to grab all its children. This approach takes n+1 connections: 1 for all parents and n number of trips to get all children for each parent.
Any advise on how to do this easier? Granted i can't get away from using stored procedures, and I can't use LINQ2SQL or EF. Would you prefer Data Tables vs DataReaders and if so how to use either with approach 1 or 2?
Thanks,
Martin
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我更喜欢在一个查询中提取所有结果,然后在一个循环中构建树
I prefer pulling all results in one query and just build the tree in one loop
您可以只包含
p.ParentId 的订单
。这可确保来自同一父级的所有子级都位于连续的行中。因此您可以读取下一行,如果父对象已更改,则创建一个新的父对象,否则将子对象添加到前一个父对象中。无需搜索唯一的父行。You could just include an
order by p.ParentId
. This ensures all children from the same parent are in consecutive rows. So you can read the next row, if the parent has changed, create a new parent object, otherwise add the child to the previous parent. No need to search for unique parent rows.我通常在牌桌上做出这个决定。有些桌子我经常需要孩子们,所以我马上就抢了。在其他情况下,访问子级是很少见的,所以我延迟加载它们。
I usually make this decision at the table level. Some tables I need the children often, so I grab them right away. In other cases accessing the children is a rarity, so I lazy-load them.
我猜想选项#2 在带宽方面比选项#1 更有效(因为您不重复任何数据)。
您可以在单个存储过程中包含两个查询,并使用 sqldataadapter 通过代码执行该过程(即
(new SqlDataAdapter(command)).Fill(myDataSet)
,其中myDataSet
将包含两个表)。从那里您可以读取第一个表,通过 ParentId 创建父级字典(在
Dictionary
中),然后只需读取第二个表中的每一行即可添加子级:伪代码可能有点偏差,但希望您能了解总体思路
I would guess option #2 would be more efficient bandwidth wise over option #1 (as you're not repeating any data).
You can have both queries in a single stored procedure, and execute the procedure through code using a sqldataadapter (i.e.
(new SqlDataAdapter(command)).Fill(myDataSet)
, wheremyDataSet
would contain the two tables).From there you'd read the first table, creating a dictionary of the parents (in a
Dictionary<int, Parent>
) by ParentId, then simply read each row in the 2nd table to add the children:The pseudo code is probably off a bit, but hopefully you get the general idea