关闭阅读器.NET时,尝试调用阅读无效

时间:2019-02-07 03:26:15

标签: c# .net sql-server

我目前有一个用于数据库访问的数据库库,并且在多个项目中使用它。我目前使用以下代码获取记录集。

  

方法

    public static IDataReader GetRs(string sql)
    {
        using (var con = NewSqlConnection())
        {
            con.Open();
            return GetRs(sql, con);
        }
    }
    public static IDataReader GetRs(string sql, SqlConnection dbconn)
    {
        using (var cmd = new SqlCommand(sql, dbconn))
        {
            int tries = 1;

            while (tries <= 3)
            {
                try
                {
                    if (dbconn.State == ConnectionState.Closed)
                    {
                        dbconn.Open();
                    }

                    DataTable myTable = new DataTable();

                    var reader = cmd.ExecuteReader();

                    myTable.Load(reader);

                    return myTable.CreateDataReader();

                    //return cmd.ExecuteReader();
                }
                catch (SqlException ex)
                {
                    if (ex.Message.Contains("Timeout expired") || ex.Number == 1205) // Deadlock 
                    {
                        Thread.Sleep(1000);
                        if (tries == 3)
                        {
                            throw ex;
                        }

                        tries += 1;
                        cmd.CommandTimeout *= 10;

                    }
                    else
                    {
                        throw ex;
                    }
                }
            }
        }

        throw new Exception("Could not get RecordSet");
    }
  

用法

public static void Test()
{
    using(var reader = GetRs("SELECT Col FROM TABLE"))
    {
        while(reader.Read())
        {
            // do stuff with data here e.g. var value = reader[0];
        }
    }
}

虽然此方法有效,但您可以看到它将整个数据集加载到内存中,从而导致缩放问题。

我尝试在GetRs(string sql, SqlConnection con)方法中替换以下代码

DataTable myTable = new DataTable();

var reader = cmd.ExecuteReader();

myTable.Load(reader);

return myTable.CreateDataReader();

并尝试仅返回return cmd.ExecuteReader();

但是在while (reader.Read())-Invalid attempt to call read when the reader is closed上引发了错误。我猜这是因为SqlConnection属性在返回IDataReader之后就被处置(并因此被关闭)。

我知道我可以用一个新的sql连接包装GetRs方法,但这意味着重写许多代码,我希望能够处理读取器和该连接。我的using(var reader = GetRs())方法。

有什么方法可以在不将整个数据集加载到内存的情况下仍然使用这些方法吗?

2 个答案:

答案 0 :(得分:1)

您可以使用Action<DataTableReader>参数向您的GetRs调用中插入代码。

尝试一下:

public static void GetRs(string sql, Action<DataTableReader> consumer)
{
    using (var con = NewSqlConnection())
    {
        con.Open();
        GetRs(sql, con, consumer);
    }
}

public static void GetRs(string sql, SqlConnection dbconn, Action<DataTableReader> consumer)
{
    using (var cmd = new SqlCommand(sql, dbconn))
    {
        if (dbconn.State == ConnectionState.Closed)
        {
            dbconn.Open();
        }
        DataTable myTable = new DataTable();
        var reader = cmd.ExecuteReader();
        myTable.Load(reader);
        consumer(myTable.CreateDataReader());
    }
}

(为清楚起见,我删除了您的try / catch代码。)

然后您这样称呼它:

public static void Test()
{
    GetRs("SELECT Col FROM TABLE", reader =>
    {
        while(reader.Read())
        {
            // do stuff with data here e.g. var value = reader[0];
        }
    });
}

答案 1 :(得分:-2)

您的连接对象已被以下行关闭

using (var con = NewSqlConnection())
{
    con.Open();
    return GetRs(sql, con);
}//Connection object gets released here 

但是,您仍将返回由SqlCommand对象使用上述连接对象创建的阅读器对象。因此,读者对象是关闭的。