关于c#:InvalidOpearationException:已经有一个打开的DataReader

InvalidOpearationException: There is already an open DataReader

你好,我通过以下代码从SQL创建控件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
string query ="SELECT * FROM [schema] WHERE idSch=@id";
            SqlCommand com = new SqlCommand(query, con);
            com.Parameters.AddWithValue("@id", result);
            con.Open();
            SqlDataReader read= com.ExecuteReader();

            while (read.Read())
            {

                createLabelCmd((int)read["x"], (int)read["y"]);


            }
            con.Close();

问题在于createLabelCmd包含SqlCommand,并且它需要一个打开的SqlConnection

内部createLabelCmd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
String ResultSitting
private void createLabelCmd(int x, int y)
    {
for (int i = 0; i < 1; i++)
        {
            var newLabel = new Label();
            newLabel.Location = new Point(x, y);
            newLabel.Text = realpocsed.ToString();
            string sitting = newLabel.Name;
            string sittingSearch = (sitting).Substring(3, 1);
            if (sittingSearch != null && kzajezdu =="kZajezdu")
            {
                string querySitting ="SELECT name, surname FROM klient WHERE sitting = @sitting AND event=@event AND year=@year";
                SqlCommand cmdSitting = new SqlCommand(querySitting, spojeni);
                cmdSitting.Parameters.AddWithValue("@sitting", sittingSearch);
                cmdSitting.Parameters.AddWithValue("@event", idEvent);
                cmdSitting.Parameters.AddWithValue("@year", klientClass.Year());

                ResultSitting = cmdSitting.ExecuteScalar().ToString().Trim(); //This might be the issue

            }

            if (kzajezdu =="kZajezdu")
            {
                newLabel.MouseHover += delegate(object sender, EventArgs e)
                {
                    ToolTip ToolTip1 = new ToolTip();
                    ToolTip1.ShowAlways = true;
                    if (sittingSearch != null)
                    {
                        ToolTip1.Show(ResultSitting, newLabel);
                    }
                    else { ToolTip1.Show("This sitting is Empty!", newLabel); }
                };

            }

            panel1.Controls.Add(newLabel);
        }

我得到一个例外:InvalidOpearationException: There is already an open DataReader associated with this Command which must be closed first.

您能帮我解决这个问题吗?

编辑为Soner G?nül建议:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try
        {
            string query ="SELECT * FROM [schema] WHERE idSch=@id";
            SqlCommand com = new SqlCommand(query, con);
            com.Parameters.AddWithValue("@id", idSch);
            con.Open();
            SqlDataReader read= com.ExecuteReader();

            while (precti.Read())
            {
                createLabelCmd((int)read["x"], (int)read["y"]);

            }
            con.Close();
        }


在其他答案中概述了问题的原因(当打开DataReader时,该阅读器使用的连接无法提供其他命令),但是许多人都无法谈论针对这种情况引入的MultipleActiveResultSets

只需更改您的连接字符串以包括此选项,您的代码就可以正常工作而没有任何变化

1
Server=yourServer;Database=yourDB;Trusted_Connection=True;MultipleActiveResultSets=true;

为完成答案,从SQL Server 2005开始提供MARS,您应该注意一些小问题。


因为当您使用打开的SqlDataReader进行循环时,已经存在打开的连接。

来自DataReaders (ADO.NET)

"You can use the ADO.NET DataReader to retrieve a read-only,
forward-only stream of data from a database.

Results are returned as the query executes, and are stored in the
network buffer on the client until you request them using the Read
method of the DataReader"

作为一般建议,使用using like;

1
2
3
4
5
6
7
using(SqlDataReader read= com.ExecuteReader())
{
    while (read.Read())
    {
       createLabelCmd((int)read["x"], (int)read["y"]);
    }
}

或在您的连接字符串中进行设置;

1
...MultipleActiveResultSets=true;


您可以将第二个连接用于createLabelCmd,也可以通过在连接字符串中添加" MultipleActiveResultSets = True"来打开初始连接中的MARS(多个活动结果集)。

http://msdn.microsoft.com/zh-cn/library/h32h3abf.aspx


我想您正在写坐式规划器,并尝试在特定位置显示标签。因此,您最好从klient表中为给定事件选择所有记录,并将它们放在DataSet中。然后遍历它(使用foreach)并创建标签。这样,只有一个命令应该发送到数据库,并且显然,您的应用程序的性能会好得多。

话虽如此,我不明白您的sittingSearch变量如何工作,我认为需要对其进行修改。


将MARS设置为True AND
确保我使用了ToList();在我的if语句和返回中
在下面的代码中,我在if语句的两种情况下都缺少toList(),在发布..将语句更新为以下work @!

之后,我在IIS 8.5上遇到了错误。

1
var varM = (id == 1) ? db.M.Where(x => x.UN== userID).ToList() : db.M.Where(x => x.EUN== userID).ToList();