【问题标题】:.Net Core cursor within a cursor.Net Core 游标内的游标
【发布时间】:2017-02-06 14:58:38
【问题描述】:

我正忙于开发一个 .Net Core Web 应用程序,我想知道是否可以在另一个游标中执行游标。

我有以下我认为可以工作的代码

string string = null;
SqlCommand collections_cur = null;
SqlCommand headings_cur = null;
int cl_idno = 0;

sqlserv.Open();

string = " select * from collections " +
         " where cl_idno >= @cl_idno ";
collections_cur = new SqlCommand(string, sqlserv);

string = " select * from headings " +
         " where hd_cl_idno = @hd_cl_idno ";
headings_cur = new SqlCommand(string, sqlserv);

collections_cur.Parameters.Add(new SqlParameters("cl_idno", 1));
using(SqlDataReader reader1 = collections_cur.ExecuteReader())
{

    while(reader1.Read())
    {

        // some stuff

        cl_idno = reader1.GetInt32(0);

        headings_cur.Parameters.Add(new SqlParameters("hd_cl_idno", cl_idno));
        using(SqlDataReader reader2 = headings_cur.ExecuteReader())
        {

            while(reader2.Read())
            {

                // more stuff

            }

        }

    }

}

sqlserv.Close();

虽然出现以下错误,但上述内容正在崩溃

InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.

我认为它会分别对待 reader1 和 reader2,但我不确定如何正确使用第二个 DataReader 对象。

PS

我知道我可以使用单个光标来做到这一点

select * from collections
left join headings on hd_cl_idno = cl_idno
where cl_idno >= 1

但我正在使用这个简化的代码,以便问题易于阅读。在某些情况下,我需要一个光标内的光标,这段代码只是为了说明问题

【问题讨论】:

  • 有些事情最好在记忆中完成.....
  • 不要重用同一个 SqlConnection 对象。这就是导致问题的原因,只需为每个命令创建一个新的 SqlConnection。
  • @GarethD 评论将解决您的异常,但您使用这种方法打开了一个痛苦的世界。
  • 我很惊讶在游标中使用游标是 C# 中的禁忌。在 TSQL、Genero 和我使用过的许多其他语言中,光标内的光标感觉非常自然
  • 如果 TSQL 中游标中的游标对您来说很自然,那么我害怕看到您的查询是什么样的。游标应该是 T-SQL(或任何 SQL 分支)中的最后手段,而且我认为在任何情况下都不会在游标中调用游标,如果我这样做会让我很痛苦曾经不得不这样做。这远非自然!

标签: c# .net sql-server asp.net-core cursor


【解决方案1】:

这似乎是 C# 开发人员不赞成的,但无论如何我有一个解决方案,如果它可能使任何人受益。您可能应该自担风险使用它,或者不使用它,但它对我有用。

我对代码做了如下调整

//
// define and initialize variables
//

string credentials = null;
SqlConnection sqlserv = null;
string lv_string = null;
SqlCommand collections_cur = null;
SqlCommand headings_cur = null;
int cl_idno = 0;

//
// connect to database
// MultipleActiveResultSets=True was added
// to allow usage of multiple cursors
//

credentials = "Data Source=(localdb)\\MSSQLLocalDB;" +
              "Initial Catalog=rescratch;" +
              "Integrated Security=True;" +
              "Connect Timeout=30;" +
              "Encrypt=False;" +
              "TrustServerCertificate=True;" +
              "ApplicationIntent=ReadWrite;" +
              "MultipleActiveResultSets=True;" +
              "MultiSubnetFailover=False";

sqlserv = new SqlConnection(credentials);

sqlserv.Open();

//
// declare cursors
//

lv_string = " select * from collections " +
            " where cl_idno >= @cl_idno ";
collections_cur = new SqlCommand(lv_string, gv_sqlserv);
collections_cur.Parameters.Add(new SqlParameters("cl_idno", 0));

lv_string = " select * from headings " +
            " where hd_cl_idno = @hd_cl_idno ";
headings_cur = new SqlCommand(lv_string, gv_sqlserv);
headings_cur.Parameters.Add(new SqlParameters("hd_cl_idno", 0));

//
// main cursor
//

// set parameter
collections_cur.Parameters["cl_idno"].Value = 1;
using(SqlDataReader lv_reader1 = collections_cur.ExecuteReader())
{

    while(lv_reader1.Read())
    {

        // some stuff

        cl_idno = lv_reader1.GetInt32(0);

        //
        // sub cursor
        //

        // set parameter
        headings_cur.Parameters["hd_cl_idno"].Value = cl_idno;
        using(SqlDataReader lv_reader2 = headings_cur.ExecuteReader())
        {

            while(lv_reader2.Read())
            {

                // more stuff

            }

        }

    }

}

sqlserv.Close();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多