首页 > 解决方案 > System.InvalidOperationException -> 与此命令关联的 DataReader [提交事务失败]

问题描述

我有这样的问题。我已将事务服务添加到我的 SQL 类。当我想在执行后提交查询时出现错误。我将粘贴代码:

//SOME OF VARIABLES IN CLASS:
private SqlConnection connection;
private SqlCommand newQuery;
private SqlTransaction transaction;
private SqlDataReader result;

//BEGINNING TRANSACTION
public void BeginTransaction(string name)
{
    try
    {
        transaction = connection.BeginTransaction(name);
    }

    catch
    {
        MessageBox.Show("Error while beginning transaction " + name);
    }
}

//COMMIT TRANSACTION
public void Commit(string text)
{
    try
    {
        transaction.Commit();
    }

    catch (Exception e)
    {
        MessageBox.Show("Couldn't commit transaction " + text + "\n\n" + e.ToString());

        try
        {
            transaction.Rollback();
        }

        catch
        {
            MessageBox.Show("Couldn't Rollback transaction " + text);
        }
    }

        transaction = null;
}

//EXECUTE QUERY METHOD
private SqlDataReader ExecuteQuery(string query)
{
    try
    {
        if (connection.State == ConnectionState.Closed)
            connection.Open();

        if (result != null)
            result.Close();

        newQuery = connection.CreateCommand();
        newQuery.CommandText = query;
        newQuery.Transaction = transaction;

        result = newQuery.ExecuteReader();
    }

    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
    }

    return result;
}

//EXAMPLE FUNCTION WITH TRANSACTION, WHICH OCCURS ERROR:
public bool DoesDatabaseExist(string dbName)
{
    BeginTransaction("DoesDatabaseExist");
    bool res = ExecuteQuery("SELECT * FROM master.dbo.sysdatabases WHERE name='" + dbName + "';").HasRows;
    Commit("Does DB Exist 211");

    return res;
}

Afrer 运行程序,我得到错误,提交没有通过。喜欢:

无法提交事务数据库是否存在 211

System.InvalidOperationException:已经有一个打开的 DataReader 与此命令关联,必须先关闭。

我还在学习 C# 编程,所以可能很容易识别错误。但不适合我。请帮忙。

在我添加事务服务之前,一切正常,我没有更改或添加任何查询或查询执行。请帮忙。

谢谢,迈克。

标签: c#sql-server

解决方案


主要问题是您使用SqlDataReader实例的方式。

您的第一个错误是将它作为类的一个字段:

private SqlDataReader result;

不要那样做(请删除该行)。

然后将函数更改为:

private SqlDataReader ExecuteQuery(string query)
{
    try
    {
        if (connection.State == ConnectionState.Closed)
            connection.Open();

        newQuery = connection.CreateCommand();
        newQuery.CommandText = query;
        newQuery.Transaction = transaction;

        var result = newQuery.ExecuteReader();
        return result;
    }

    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
        throw;
    }
}

这确保了上述函数的每次调用都返回它自己的SqlDataReader.

好的,现在是来电者。您当前正在使用:

bool res = ExecuteQuery("SELECT * FROM master.dbo.sysdatabases WHERE name='" + dbName + "';").HasRows;
Commit("Does DB Exist 211");

这是不正确的,因为ExecuteQuery返回的SqlDataReader是您没有正确清理的。将其更改为:

var results = ExecuteQuery("SELECT * FROM master.dbo.sysdatabases WHERE name='" + dbName + "';");
using (results)
{
    bool res = results.HasRows;
}
Commit("Does DB Exist 211");

using将确保SqlDataReader正确处置(关闭)。

请注意,您的代码中仍然存在许多其他问题。例如:

  • 您使用显式事务是没有意义的,因为您正在执行单个 SELECT 语句
  • 您的其他字段(用于命令、连接和事务)也是一个坏主意(就像result以前一样)
  • 您的代码对SQL 注入开放
  • 您可能希望阅读Dapper

推荐阅读