Многократная вставка данных в таблицу SQL с помощью одной кнопки в Windows Forms - PullRequest
6 голосов
/ 30 марта 2011

Я вставляю данные из формы 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 ]

11 голосов
/ 30 марта 2011

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

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

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

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

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

2 голосов
/ 30 марта 2011

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

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

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

1 голос
/ 30 марта 2011

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

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

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

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

Еще один потенциальный способ исправить это на установить для MARS (Multiple Active Result Set) значение true в строке подключения.

0 голосов
/ 30 марта 2011

Вы можете попробовать:

cmd.ExecuteReader(CommandBehavior.CloseConnection);
...