如何从SQL读取父子数据?

发布于 2024-10-21 19:22:12 字数 1199 浏览 3 评论 0原文

再次感谢您发布的所有精彩答案!

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

别理我 2024-10-28 19:22:12

我更喜欢在一个查询中提取所有结果,然后在一个循环中构建树

    SELECT p.ParentId as 'ParentId', null as 'ChildId'
    FROM Parents p
    UNION ALL
    SELECT c.ParentId as 'ParentId', c.ChildId as 'ChildId'
    FROM Children c

    List<Parent> result = new List<Parent>();
    Parent current;
    while (dr.Read())
    {
      if (string.isNullOrEmpty(dr['ChildId']))
      {
        //create and initialize your parent object here and set to current
      }
      else if (!string.isNullOrEmpty(dr['ChildId']) 
                && dr['ParentId'].ToString().Equals(current.ParentId.ToString())
      {
        //create and initialize child
        //add child to parents child collection
      }
    }

I prefer pulling all results in one query and just build the tree in one loop

    SELECT p.ParentId as 'ParentId', null as 'ChildId'
    FROM Parents p
    UNION ALL
    SELECT c.ParentId as 'ParentId', c.ChildId as 'ChildId'
    FROM Children c

    List<Parent> result = new List<Parent>();
    Parent current;
    while (dr.Read())
    {
      if (string.isNullOrEmpty(dr['ChildId']))
      {
        //create and initialize your parent object here and set to current
      }
      else if (!string.isNullOrEmpty(dr['ChildId']) 
                && dr['ParentId'].ToString().Equals(current.ParentId.ToString())
      {
        //create and initialize child
        //add child to parents child collection
      }
    }
看透却不说透 2024-10-28 19:22:12

使用这种方法我必须找到
所有唯一的父行,然后
读所有的孩子。

您可以只包含p.ParentId 的订单。这可确保来自同一父级的所有子级都位于连续的行中。因此您可以读取下一行,如果父对象已更改,则创建一个新的父对象,否则将子对象添加到前一个父对象中。无需搜索唯一的父行。

Using this approach I'd have to find
all the unique parent rows, and then
read all the children.

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.

心病无药医 2024-10-28 19:22:12

我通常在牌桌上做出这个决定。有些桌子我经常需要孩子们,所以我马上就抢了。在其他情况下,访问子级是很少见的,所以我延迟加载它们。

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.

困倦 2024-10-28 19:22:12

我猜想选项#2 在带宽方面比选项#1 更有效(因为您不重复任何数据)。

您可以在单个存储过程中包含两个查询,并使用 sqldataadapter 通过代码执行该过程(即 (new SqlDataAdapter(command)).Fill(myDataSet),其中 myDataSet 将包含两个表)。

从那里您可以读取第一个表,通过 ParentId 创建父级字典(在 Dictionary 中),然后只需读取第二个表中的每一行即可添加子级:

parents[(int)myDataSet.Tables[1]["ParentId"]].Children.Add(new Child() { etc } );

伪代码可能有点偏差,但希望您能了解总体思路

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), where myDataSet 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:

parents[(int)myDataSet.Tables[1]["ParentId"]].Children.Add(new Child() { etc } );

The pseudo code is probably off a bit, but hopefully you get the general idea

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文