在 C# 中与此命令错误关联的打开数据读取器

An open datareader associated with this command error in C#

我想构建一个简单的循环来检查来自 SQL 服务器的传入数据,将其与文本字段进行比较,如果没有重复则执行非查询。

我写了这段代码:

try
{
    bool exists = false;
    conn = new SqlConnection(DBConnectionString);

    SqlCommand check_user = new SqlCommand("SELECT usrEmail FROM tblUsers", conn);
    SqlCommand add_user = new SqlCommand("INSERT INTO tblUsers (usrEmail, usrPassword, usrRealname, usrIsowner) VALUES (@email, @pass, @name, @owner)", conn);
    // (I have removed all the paramaters from this code as they are working and irrelevant)
    conn.Open();

    SqlDataReader check = check_user.ExecuteReader();

    while (check.Read())
    {
        if (Convert.ToString(check[0]) == UserEmail.Text)
        {
            MessageBox.Show("The email you entered already exists in the system.");
            exists = true;
            break;
        }
    }

    if (exists == false)
    {
        add_user.ExecuteNonQuery();
    }
    else
    {
        return;
    }
}
catch (Exception ex)
{
    MessageBox.Show("There was a problem uploading data to the database. Please review the seller's details and try again. " + ex.Message);
    return;
}
finally
{
    conn.Close();
}

我使用了断点并看到代码运行 while 循环很好,但是当它到达 ExecuteNonQuery 命令时,它 returns 一条错误消息:

there is already an open datareader associated with this command which must be closed first

我尝试使用 check.Close(); 命令,但当我这样做时,由于无法理解的原因,它突然卡在重复的电子邮件错误消息中。 此外,我尝试了一个修复程序,其中数据实际上被发送到数据库(我在 SQL Server Management Studio 中看到它),但仍然给出错误消息......这更奇怪,因为非查询命令是此函数中的最后一个。如果成功了,为什么会成功?

我在网站上搜索了答案,但最常见的答案是 MARS(我不知道那是什么)或数据集,我不想在这种情况下使用它们。

这里有简单的解决方法吗?我是否遗漏了代码中的某些内容?

最简单的出路是:

using(SqlDataReader check = check_user.ExecuteReader())
{
    while (check.Read())
    {
        if (Convert.ToString(check[0]) == UserEmail.Text)
        {
            MessageBox.Show("The email you entered already exists in the system.");
            exists = true;
            break;
        }
    }
}

也就是说,这段代码存在一些严重的问题。

首先,您真的不想阅读 所有 用户只是为了检查电子邮件地址是否已被占用。 select count(*) from tblUsers where usrEmail = @email 很好...

...或不,因为存在竞争条件的可能性。您应该做的是在 usrEmail 列和 insert into tblUsers 上添加一个唯一约束,捕获违规。或者,如果您愿意,可以使用 merge

接下来,您真的不希望到处都是数据访问代码。至少将其分解为单独的 classes/methods。