如何将 .NET 对象集合(父子)层次结构传递给 SQL Server 存储过程

Posted

技术标签:

【中文标题】如何将 .NET 对象集合(父子)层次结构传递给 SQL Server 存储过程【英文标题】:How to pass .NET Collection of objects (Parent-Child) hierarchy to a SQL Server stored procedure 【发布时间】:2016-12-23 17:20:32 【问题描述】:

我需要将 .NET 集合传递给存储过程。我的收藏包含 1000 条记录。每条记录包含2-3个其他类型的子对象。

我只需要通过从 .NET 调用存储过程来一次插入它们。

我已经尝试过 TVP(表值参数),但这根本无法满足我的需求。

对于每个根级记录,我需要通过传递根记录及其对应的子记录来调用存储过程。这使得整个过程非常缓慢。

这就是为什么我正在寻找一种方法,以便我可以一次传递整个层次结构列表,并且在存储过程中,通过循环和迭代子记录,我可以插入父子记录。

我怎样才能做到这一点?

【问题讨论】:

尝试使用 XML 并将其解压到存储过程中的临时表中。它对我来说工作得很快。 表值参数是一个很好的方法。只需传递 2 个表,一个用于父级,另一个用于子级,并使用一些键来关联它们。 @Alejandro :目前,我以几乎相同的方式通过。而是将整个父级作为一张表传递,将整个子级作为另一张表传递,我正在传递一个父级记录及其对应的子级列表。但这真的很慢,因为我需要插入 100K 父记录。此外,对于每个单亲父母,都有 3-4 个孩子与之关联。 这可能是问题的根源。尝试一次完成所有这些,而不是一个接一个。我想大部分开销来自重复的网络往返而不是查询本身。 是的,这就是我所知道的。所以,解决方案是一次传递整个层次结构,然后让 SQL 在内部完成。所以问题归结为:如何一次传递整个层次结构(例如 List consignments,其中每个 consignment 包含 List 【参考方案1】:

我实际上是在 3 周前才这样做的。

    创建一个“临时”关联键(我使用 GUID)将父级和子级链接在一起,因为您没有数据库 ID(临时键永远不会保存在数据库中) 调用 TVP 存储过程。在两个单独的表变量中传递所有父母和所有孩子 创建临时表或表 var 来存储临时 ID/数据库 ID 关系 使用带有 OUTPUT 的 merge 语句将 Inserted.Id 值和 temp id 获取到步骤 3 中创建的临时表中 使用 CTE 和合并语句使用父记录中的实际 DB id 插入子记录

这里有几个关于该过程的链接以及“真实”示例:

merge parent and child SQL Server tables

T-SQL - Insert Data into Parent and Child Tables

【讨论】:

Keith : 你能告诉我如何将父子层次列表从 .NET 传递到存储过程吗?我不想在传递整个列表时打破父子层次结构。因为,以后很难将每个子实体与其对应的父实体关联起来。 我已经在我的答案中编写了代码示例(此链接中的第二个链接),但仅限于 sql 部分。您需要 .net 端示例吗? 是的,如果你能管理详细的答案,那就太好了:-) @Usman 你知道如何从你的列表中填充数据表吗? 是的,我知道如何在 c# 中填充数据表以将其作为 TVP 传递给存储过程【参考方案2】:

您可以使用 XML 将记录及其子项传递给存储过程。例如

DECLARE @xml XML = '<root>
<parent value="213">
    <child childValue="1111"></child>
    <child childValue="1112"></child>
</parent>
<parent value="2313">
    <child childValue="3333"></child>
    <child childValue="3332"></child>
</parent>
</root>'

然后你可以做很多方法,其中之一是对记录进行非规范化并保存到临时表以供进一步处理

    SELECT
    T.c.value('parent::*/@value', 'INT') AS ParentValue,
    T.c.value('@childValue', 'INT') AS ChildValue
    FROM @xml.nodes('/root[1]/parent/child') T(c)

结果会是这样的

    ParentValue  ChildValue
    213          1111
    213          1112
    2313         3332
    2313         3333

【讨论】:

很抱歉,我根本无法使用 XML。这在应用程序中是额外开销的。我一次处理 10 万条记录,并在内存 xml 中构建包含 80 列包含 10 列子项的单父记录,这将是一个非常糟糕的主意。

以上是关于如何将 .NET 对象集合(父子)层次结构传递给 SQL Server 存储过程的主要内容,如果未能解决你的问题,请参考以下文章

Vue 组件层次结构和传递数据

如何使用 GraphQL.Net 和 c# 将集合传递给 GraphQL 突变?

如何知道父子 C# 列表中的深度计数 [关闭]

如何在类层次结构中传递智能指针

将模态视图控制器添加到父子视图控制器层次结构

如何从 dll 正确返回 std::list