2

OTServerと呼ばれるゲームサーバーのデータベースマネージャーをプログラミングしていますが、executereader()を2回使用すると問題が発生します。コードは次のとおりです。

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

2 に答える 2

4

推奨される解決策: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();
}

問題の想定される原因: DB接続オブジェクトは、データリーダーを追跡するために内部の簿記を行う場合があります。同様のシナリオで、一度に1つしか許可されていないことがわかりましたDataReader。したがって、コードの問題は、明示的にdを実行していないCloseのに、2番目のデータリーダーを実行するときに最初のデータリーダーがまだ使用されていると接続オブジェクトが判断することだと思います。ReaderDispose


その上...このコードを単純化してみませんか:

        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;

(これにより、繰り返しの入力をかなり節約できます。)

于 2010-11-21T14:25:28.130 に答える
3

さて、あなたのコードが正しいと仮定すると、あなたはあなたのコードで示すように2つのリーダーを実行することに問題はないはずです。コマンドなどを破棄しないために問題が発生している可能性があります。このようなアプローチをお勧めします(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();
于 2010-11-21T14:31:35.153 に答える