C# 中的 SQL 嵌套查询和连接打开问题

本文关键字:连接 问题 查询 中的 SQL 嵌套 | 更新日期: 2023-09-27 17:57:00

我有三个表,我的要求是使用每个表的父记录来获取它们的记录。

所以我有三个疑问。下面是一个代码示例:

第一个查询

SQLConnection con = new SQLConnection("connectionstring");
SQLCommand cmd1 = new SQLCommand (1stQuery,con);
SQLDataReader rs1 = cmd1.DataReader();
while (rs1.Read()) {
// Making 2nd Query, 2nd Query is using 1st Query result
SQLCommand cmd2 = new SQLCommand(2ndQuery,con);
SQLDataReader rs2 = cmd2.DataReader();
while (rs2.Read()){
//Making 3rd Query using 2nd Query result
}
}

它给出的错误是已经有一个打开的 DataReader。我不想关闭 SQL 连接并为每个查询打开它,因为这会影响性能。

我只想对所有查询使用一个 SQL 连接。

C# 中的 SQL 嵌套查询和连接打开问题

您不需要关闭连接。问题(如错误所示)是您在启动下一个 DataReader 之前没有关闭一个 DataReader。

正如 Oded 所说,你有一个"选择 N+1"的问题,但为了这个答案,让我们忽略它。

最简单的方法是在开始读取下一个数据集之前将整个第一个数据集读入内存:

var list1 = new List<Foo>();
using (var rdr1 = cmd1.ExecuteReader())
{
    list1.Add(...);
}
var list2 = new List<Bar>();
var cmd2 = ...;
foreach (var item in list1)
{
    // assign parameters to cmd2 from item
    using (var rdr2 = cmd2.ExecuteReader())
    {
        list2.Add(...);
    }
}

。等等。

另一个选项是在连接上启用 MARS,这样您就可以同时激活多个 DataReader。这几乎总是一个坏主意,所以让我们假装我从来没有建议过它。

如果要嵌套对数据库的调用,则需要使用不同的连接。

在这里,在循环中调用数据库时遇到了一个更严重的问题 - 也称为 N+1 问题。

我建议重写数据库和应用程序逻辑 - 使用数据库中的联接将单独的查询合并为一个,并更改逻辑以使用结果。

我建议使用ExecuteDataSet。它将包含所有三个查询的结果。移动,这些查询应在存储过程中执行。

否则,您将邀请 SQL 注入

SQL 注入

将连接字符串的 MultipleActiveResultssets 属性设置为 true,但代码的性能很差。尝试将查询包装在存储过程中以避免循环。