开发者

Is it possible to use ExecuteReader() twice?

I'm programming a database manager for a gameserver called OTServer, and I'm having problems using executereader() the second time. Here's code:

    private void button1_Click(object sender, EventArgs e)
    {
        Form1 f = new Form1();
        MySqlConnection conn = new MySqlConnection();
        conn.ConnectionString = "Server=" + f.GetText1().Text + ";Username=" + f.GetText2().Text + ";Pwd=" + f.GetText3().Text + ";Database=" + f.GetText4().Text + ";";
        conn.Open();
        MySqlCommand cmd = new MySqlCommand("SELECT * FROM `players` WHERE name = @Name", conn);
        cmd.Parameters.AddWithValue("@Name", textBox1.Text);

        MySqlDataReader Reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
        while (Reader.Read())
        {
            label7.Text = (string)Reader[1];
            label7.Show();
            label8.Text = Reader[5].ToString();
            label8.Show();
            if ((int)Reader[6] == 1)
            {
                label9.Text = "Sorcerer (1)";
            }
            if ((int)Reader[6] == 2)
            {
                label9.Text = "Druid (2)";
            }
            if ((int)Reader[6] == 3)
            {
                label9.Text = "Paladin (3)";
            }
            if ((int)Reader[6] == 4)
            {
                label9.Text = "Knight (4)";
            }

            if ((int)Reader[6] == 0)
            {
                label9.Text = "None (0)";
            }
            label9.Show();

            if ((int)Reader[3] == 1)
            {
                label10.Text = "Player";
            }

            if ((int)Reader[3] == 2)
            {
                label10.Text = "Tutor";
            }

            if ((int)Reader[3] == 3)
       开发者_C百科     {
                label10.Text = "Senior Tutor";
            }

            if ((int)Reader[3] == 4)
            {
                label10.Text = "Gamemaster";
            }

            if ((int)Reader[3] == 5)
            {
                label10.Text = "Community Manager";
            }

            if ((int)Reader[3] == 6)
            {
                label10.Text = "God";
            }

            if ((int)Reader[3] < 1 || (int)Reader[3] > 6)
            {
                label10.Text = "Unknown";
            }

            label10.Show();

            label13.Text = "Account: " + Reader[4].ToString();
            label13.Show();
        }
        Reader.Close();

        cmd = new MySqlCommand("SELECT * FROM accounts WHERE id = @Account_ID", conn);
        cmd.Parameters.AddWithValue("@Account_ID", label13.Text);
        Reader = cmd.ExecuteReader(CommandBehavior.SingleRow);

        while (Reader.Read())
        {
            label11.Text = (string)Reader[0];
            label11.Show();
        }
        Reader.Close();
    }


Suggested solution: Try putting a using block around your DataReader, or call Dispose on it:

using (DataReader Reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
    // ...do something with your data reader... then finish by:
    Reader.Close();
}  // <-- Reader.Dispose() called automatically at the end of using block.

// ...prepare second command...

// the same again for the second command:
using (DataReader Reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
    // ...
    Reader.Close();
}

Assumed cause of your problem: The DB connection object may do some internal book-keeping to keep track of data readers. I've found out in a similar scenario that you're only allowed one DataReader at a time. So I believe the problem with your code is that, while you Close the Reader, you haven't explicitly Disposed it, so the connection object thinks the first data reader is still in use when you execute the second one.


Besides... why not simplify this code:

        if ((int)Reader[6] == 1)
        {
            label9.Text = "Sorcerer (1)";
        }
        if ((int)Reader[6] == 2)
        {
            label9.Text = "Druid (2)";
        }
        ...

to a switch statement?:

        int x = (int)(Reader[6]);
        string label9Text = string.Empty;

        switch (x)
        {
            case 1:  label9Text = "Sorcerer (1)";  break;
            case 2:  label9Text = "Druid (2)";     break;
            ...
        }

        label9.Text = label9Text;

(That would save you quite a bit of repetitive typing.)


Well, assuming that your code is correct you shouldn't have problem in executing two readers as you show in your code. Maybe you have problems because of not disposing commands or something else. I recommend an approach like this (Example made with Northwind db):

using (SqlConnection connection = new SqlConnection("Data Source=.\\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=SSPI;"))
        {
            connection.Open();

            using (SqlCommand command = new SqlCommand("SELECT * FROM Orders", connection))
            {
                using (SqlDataReader reader = command.ExecuteReader(System.Data.CommandBehavior.SingleRow))
                {
                    while (reader.Read())
                    {
                        Console.WriteLine(reader.GetString(2));
                    }
                }
            }

            using (SqlCommand command = new SqlCommand("SELECT * FROM Products", connection))
            {
                using (SqlDataReader reader = command.ExecuteReader(System.Data.CommandBehavior.SingleRow))
                {
                    while (reader.Read())
                    {
                        Console.WriteLine(reader.GetString(1));
                    }
                }
            }
        }

You should clean your code when recognizing the type of player. Create an enum instead:

public enum PlayerType
{
    None = 0,
    Sorcerer = 1,
    Druid = 2,
    Paladin = 3
}

And then do the following while reading:

PlayerType playerType = (PlayerType)reader.GetInt32(6);
label9.Text = playerType.ToString();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜