Можно ли использовать ExecuteReader () дважды? - PullRequest
1 голос
/ 21 ноября 2010

Я программирую менеджер базы данных для игрового сервера под названием OTServer, и у меня возникают проблемы с использованием executereader () во второй раз. Вот код:

    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)
            {
                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();
    }

Ответы [ 2 ]

3 голосов
/ 21 ноября 2010

Предлагаемое решение: Попробуйте наложить using блок вокруг DataReader или позвоните Dispose:

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();
}

Предполагаемая причина вашей проблемы: Объект соединения с БД может вести некоторую внутреннюю бухгалтерию для отслеживания устройств чтения данных.В похожем сценарии я обнаружил, что вам разрешается только один DataReader за раз.Поэтому я считаю, что проблема с вашим кодом заключается в том, что, хотя вы Close Reader явно не Dispose d, поэтому объект подключения думает, что первое устройство чтения данных все еще используется, когда вы выполняете второеone.


Кроме того ... почему бы не упростить этот код:

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

до switch оператора?:

        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;

(Это избавит вас от необходимости многократного набора текста).

2 голосов
/ 21 ноября 2010

Что ж, если ваш код верен, у вас не должно возникнуть проблем с выполнением двух программ чтения, как показано в коде. Возможно, у вас проблемы из-за того, что вы не располагаете командами или чем-то еще. Я рекомендую такой подход (Пример, сделанный с помощью 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));
                    }
                }
            }
        }

Вы должны очистить свой код при распознавании типа игрока. Вместо этого создайте перечисление:

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

А затем выполните следующее при чтении:

PlayerType playerType = (PlayerType)reader.GetInt32(6);
label9.Text = playerType.ToString();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...