Вставка данных несколько раз в таблицу SQL из одной кнопки в Windows Forms

я вставляю данные из Windows Forms форма в базу данных SQL, как показано ниже:

public partial class Form1 : Form
{
    SqlConnection c = new SqlConnection();
    string q = "Trusted_Connection = true; ";

    public Form1()
    {
        InitializeComponent(); c.ConnectionString = q;
        MessageBox.Show("Connecting Database");
    }

    private void button1_Click(object sender, EventArgs e)
    {
        string w = "insert into checkmultiuser(username) values (@username)";

        SqlCommand cmd = new SqlCommand(w, c);
        cmd.Parameters.Add("@username", SqlDbType.VarChar);
        cmd.Parameters["@username"].Value = textBox1.Text;
        cmd.ExecuteReader();
    }

но когда я снова нажимаю кнопку, он говорит: "с этой командой уже связан открытый DataReader, который должен быть закрыт первым.".

Как мне справиться с этим?

*обновление: * я изменил код события нажатия кнопки, как показано ниже:

private void button1_Click(object sender, EventArgs e)
{
    **c.Open();**

    string w = "insert into checkmultiuser(username) values (@username)";

    SqlCommand cmd = new SqlCommand(w, c);

    cmd.Parameters.Add("@username", SqlDbType.VarChar);
    cmd.Parameters["@username"].Value = textBox1.Text;
    //cmd.ExecuteNonQuery();
    cmd.ExecuteReader();
    **c.Close();**
}

каковы его недостатки? Один был бы таким снова и снова. опять соединение открывается и закрывается при нажатии кнопки.

4 ответов


читателю нужно открытое соединение, потому что вы извлекаете результаты по одному за раз. Вы захотите сделать ExecuteNonQuery () для вставок, удалений и обновлений. После этого Вам также нужно закрыть соединение. Альтернативой является обертывание вставок в цикл, если вы планируете сделать несколько вставок.

есть несколько способов сделать это. Этот способ полезен, если вы планируете повторно использовать один и тот же объект подключения и объект команды снова и снова опять:

public partial class Form1 : Form
{
    SqlConnection _cn;
    SqlCommand _cmd;

    const string ConnString = "Enter your connection string here";
    readonly string _insertQuery;
    const string UsernameParm = "@username";

    public Form1()
    {
        InitializeComponent(); 
        _cn = new SqlConnection(ConnString);

        _cmd = new SqlCommand(InsertQuery, _cn);        
        _cmd.Parameters.Add(UsernameParm, SqlDbType.VarChar);

        _insertQuery = String.Format("INSERT INTO checkmultiuser(username) VALUES ({0})",
                                     UsernameParm);
    }

    private void button1_Click(object sender, EventArgs e)
    {        
        _cmd.Parameters[UsernameParm].Value = textBox1.Text;

        try
        {
            _cn.Open();
            _cmd.ExecuteNonQuery();
        }
        catch (Exception ex) // probably best to catch specific exceptions
        {
            // handle it
        }
        finally
        {
            _cn.Close();
        }
    }
}

просто не забудьте избавиться от объектов connection и command (когда форма закрывается или где-либо имеет смысл для вашего приложения).

использование блоков является более безопасной альтернативой, но они будут избавляться от объекта каждый раз (хотя соединения используют пул соединений по умолчанию):

public partial class Form1 : Form
{
    const string ConnString = "Enter your connection string here";
    readonly string _insertQuery;
    const string UsernameParm = "@username";

    public Form1()
    {
        InitializeComponent();             

        _insertQuery = String.Format("INSERT INTO checkmultiuser(username) VALUES ({0})",
                                     UsernameParm);
    }

    private void button1_Click(object sender, EventArgs e)
    {  
        using (var cn = new SqlConnection(ConnString))
        {
            using (var cmd = new SqlCommand(InsertQuery, cn))
            {
                cmd.Parameters.Add(UsernameParm, SqlDbType.VarChar);
                cmd.Parameters[UsernameParm].Value = textBox1.Text;

                cn.Open();
                cmd.ExecuteNonQuery();
            }
        }
    }
}

любая комбинация будет работать. Вы можете настроить соединение один раз и просто обернуть объект command в using блок. Я знаю, что некоторые люди не являются поклонниками вложенных блоков (так как за кулисами это try (try finally) наконец)).


что сказал Джейсон.

пока вы там, возможно, стоит немного изменить код на:

private void button1_Click(object sender, EventArgs e)

{
  string w = "insert into checkmultiuser(username) values (@username)";
  c.Open();
  using (SqlCommand cmd = new SqlCommand(w, c))
  {
     cmd.Parameters.Add("@username", SqlDbType.VarChar);
     cmd.Parameters["@username"].Value = textBox1.Text;
     cmd.ExecuteNonQuery();
  }

}

для обеспечения правильного удаления объектов.

может быть, положить его в try{} блок тоже, и закройте соединение в finally{ c.Close();}


прежде всего, вы должны использовать ExecuteNonQuery для обработки вставок, обновлений и удаления. ExecuteNonQuery используется, когда вы не ожидаете возврата значения из базы данных.

но если вы действительно хотите использовать DataReader в другой ситуации, вы должны использовать его, как показано ниже.

using (SqlDataReader reader= cmd.ExecuteReader())
{
        while (reader.Read())
        {
            //Do the reading
        }
 }

Это гарантирует, что SqlDataReader закрывается, как только намеченная работа выполнена.

другой потенциал исправить это установить MARS (несколько активных результирующих наборов) в правда в строке подключения.


можно попробовать :

cmd.ExecuteReader(CommandBehavior.CloseConnection);