Вставка записей в базу данных


Я написал следующий код для вставки записей в базу данных. Пользователь выбирает строки из RadGrid и вставить команда выполняется, когда пользователь нажимает кнопку. Я провожу много времени, пытаясь сделать эту работу (на данный момент ничего не происходит когда я нажимаю на кнопку). Однако, я просто понял, что мой подход-это, наверное, очень неэффективным из-за того, что она приведет к применению многократное Открытие и закрытие соединения с базой данных. Хотя я имею дело с только несколько сотен записей, я хотел бы следовать рекомендациям, насколько это возможно.

Как бы вы переписать этот код, чтобы быть более эффективным? Мое чутье подсказывает, что было бы лучше собрать все новые рекорды, а потом разбираться с ними в качестве коллекции.

    protected void RadButton2_Click(object sender, EventArgs e)
{
    foreach (GridDataItem item in RadGrid1.SelectedItems)
    {
        //GridDataItem item = (GridDataItem)RadGrid1.SelectedItems;
        int UserID = Convert.ToInt16(item["UserID"].Text);
        string Type = "D";
        DateTime Date = DateTime.Now;
        string Description = "Monthly Storage Fee - Tag: " + item["PackageTag"].Text + Label3.Text;
        Int32 AmountDue = Convert.ToInt32(item["AmtDue"].Text);


        string connectionString = ConfigurationManager.ConnectionStrings["Foo"].ConnectionString;
        SqlConnection connection = new SqlConnection(connectionString);

        try
        {

            SqlCommand cmd = new SqlCommand("INSERT INTO Billing (UserID, Type, Date, Description, Amount) VALUES (@UserID, @Type, @Date, @Description, @AmountDue)", connection);
            cmd.Parameters.AddWithValue("@UserID", UserID);
            cmd.Parameters.AddWithValue("@Type", Type);
            cmd.Parameters.AddWithValue("@Date", Date);
            cmd.Parameters.AddWithValue("@Description", Description);
            cmd.Parameters.AddWithValue("@AmountDue", AmountDue);

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

        catch
        {
            Label4.Text = "uh oh";
        }

        finally
        {
            connection.Close();
        }


59558
6
задан 28 июня 2011 в 01:06 Источник Поделиться
Комментарии
9 ответов

Это не лучшая практика, но простая логика.

Почему вы добавить внутри цикла следующим образом (без изменения) параметров ?

    string Type = "D";
DateTime Date = DateTime.Now;
string connectionString =
ConfigurationManager.ConnectionStrings["Foo"].ConnectionString;

Вытащить их из петли.

Второе место соединение в использовании, и совершенно вне цикла, поэтому вам нужно открыть его и закрыть его все время.

protected void RadButton2_Click(object sender, EventArgs e)
{
//GridDataItem item = (GridDataItem)RadGrid1.SelectedItems;
string Type = "D";
DateTime Date = DateTime.Now;

string connectionString = ConfigurationManager.ConnectionStrings["Foo"].ConnectionString;
SqlConnection connection = new SqlConnection(connectionString);

using(SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
foreach (GridDataItem item in RadGrid1.SelectedItems)
{
try
{
string Description = "Monthly Storage Fee - Tag: " + item["PackageTag"].Text + Label3.Text;
Int32 AmountDue = Convert.ToInt32(item["AmtDue"].Text);
int UserID = Convert.ToInt16(item["UserID"].Text);

using (SqlCommand cmd = new SqlCommand("INSERT INTO Billing (UserID, Type, Date, Description, Amount) VALUES (@UserID, @Type, @Date, @Description, @AmountDue)", connection))
{
cmd.Parameters.AddWithValue("@UserID", UserID);
cmd.Parameters.AddWithValue("@Type", Type);
cmd.Parameters.AddWithValue("@Date", Date);
cmd.Parameters.AddWithValue("@Description", Description);
cmd.Parameters.AddWithValue("@AmountDue", AmountDue);

cmd.ExecuteNonQuery();
}
}
catch
{
Label4.Text = "uh oh";
}
}
}
}

Нужны дополнительные проверки, если соединение открыто или не

6
ответ дан 28 июня 2011 в 01:06 Источник Поделиться

Пока у вас есть доступ к SQL Server 2008, Вы можете воспользоваться ТВП (возвращающая табличное значение параметров), которая является функцией, которая была добавлена в версии 2008.

Вот две статьи, которые помогут вам начать работу. Первая статья имеет одну ключевую часть информации, которую легко пропустить, когда вы впервые приступая к работе с ПВ. Вы не только должны определить тип таблицы, вы должны предоставить права на выполнение нового типа ТВП:


  1. http://www.sqlteam.com/article/sql-server-2008-table-valued-parameters

  2. http://blog.sqlauthority.com/2008/08/31/sql-server-table-valued-parameters-in-sql-server-2008/

Обратите внимание, что при ПВ себя только для чтения, вы можете использовать их, чтобы напрямую вставить в таблицу, которая даст вам еще большую защиту от SQL-инъекций и сокращает количество рейсов в и из базы данных для того, чтобы вставить небольшую партию записей в вашу базу данных.

Надеюсь, что это помогает!

Джефф

2
ответ дан 28 июня 2011 в 03:06 Источник Поделиться

Что-то вроде этого: вам потребуется только 1 подключение в этом случае

protected void RadButton2_Click(object sender, EventArgs e)
{
string connectionString = ConfigurationManager.ConnectionStrings["Foo"].ConnectionString;
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
try
{
foreach (GridDataItem item in RadGrid1.SelectedItems)
{
//GridDataItem item = (GridDataItem)RadGrid1.SelectedItems;
int UserID = Convert.ToInt16(item["UserID"].Text);
string Type = "D";
DateTime Date = DateTime.Now;
string Description = "Monthly Storage Fee - Tag: " + item["PackageTag"].Text + Label3.Text;
Int32 AmountDue = Convert.ToInt32(item["AmtDue"].Text);

try
{

SqlCommand cmd = new SqlCommand("INSERT INTO Billing (UserID, Type, Date, Description, Amount) VALUES (@UserID, @Type, @Date, @Description, @AmountDue)", connection);
cmd.Parameters.AddWithValue("@UserID", UserID);
cmd.Parameters.AddWithValue("@Type", Type);
cmd.Parameters.AddWithValue("@Date", Date);
cmd.Parameters.AddWithValue("@Description", Description);
cmd.Parameters.AddWithValue("@AmountDue", AmountDue);
cmd.ExecuteNonQuery();
}

catch
{
Label4.Text = "uh oh";
}

finally
{

}
}
}
catch
{

}
finally
{
connection.Close();
}

1
ответ дан 28 июня 2011 в 01:06 Источник Поделиться

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

Преимущества открытия/закрытия соединения во время подобных операций заключается в том, что если код будет делать трудоемкие вещи, то соединение будет доступна для других потоков приложения, и уменьшить количество одновременных соединений, которые вы используете. Конечно, все зависит от дизайна.

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

1
ответ дан 28 июня 2011 в 01:06 Источник Поделиться


  1. Я не думаю, что это хорошая идея, чтобы вызывающий код базе на странице пользовательского интерфейса. Смотрите здесь

  2. Рассматривали ли Вы создание уровня данных с использованием фреймворка лица (или Linq2SQL). Тогда вместо того, чтобы писать все запросы вручную, вы можете заниматься типизированных объектов.

  3. Хотя вы должны делать то, что Аристос указал в любом случае (даже с EF, вы должны создать контекст на уровне предложенных Аристос для подключения)

  4. После этого, возможно, вы сможете использовать систему.Резьбонарезной.Задачи или фоновый поток worker, чтобы сделать экономию в отдельном потоке.

  5. Я вижу, что вы делаете конкатенацию строк с "+", попробуйте воспользоваться строкой.функция concat или строку.формат.

  6. Вместо использования преобразования.ToInt32(пункт["AmtDue"].Текст) рассмотреть возможность использования инт.Метод tryparse() шаблон для преобразования текста в инт.

  7. Рассмотрите использование FxCop для выявления потенциальных проблем в коде.

1
ответ дан 28 июня 2011 в 03:06 Источник Поделиться

Одна вещь, которую я заметил, когда смотрю на другие ответы, это не только создание подключения в пределах внутреннего цикла, вы строили команду запроса несколько раз, а также.

Это было время, поскольку я сделал много не SQL кодирования, но я думаю, что то, что вы ищете должно быть больше примерно следующим образом. Вы не должны очистить ваш список параметров между вызовами. Также, если идентификатор пользователя-это же на форму для каждой строки, Я бы только сделать это преобразование как хорошо.

Я пытался распространить пример Аристос предусмотрено потянуть даже больше из цикла foreach и только создание sqlcommand объект один раз, чтобы использовать все звонки.

protected void RadButton2_Click(object sender, EventArgs e)
{
try
{
string Type = "D";
DateTime Date = DateTime.Now;

string connectionString = ConfigurationManager.ConnectionStrings["Foo"].ConnectionString;
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();

SqlCommand cmd = new SqlCommand("INSERT INTO Billing (UserID, Type, Date, Description, Amount) VALUES (@UserID, @Type, @Date, @Description, @AmountDue)", connection);

cmd.Parameters.Add("@UserID", SqlDbType.Int);
cmd.Parameters.Add("@Type", SqlDbType.Int);
cmd.Parameters.Add("@Date", SqlDbType.Datetime);
cmd.Parameters.Add("@Description", SqlDbType.NChar, 80);
cmd.Parameters.Add("@AmountDue", SqlDbType.Money);

cmd.Parameters("@Type").Value = Type;
cmd.Parameters("@Date").Value = Date;

foreach (GridDataItem item in RadGrid1.SelectedItems)
{
//GridDataItem item = (GridDataItem)RadGrid1.SelectedItems;
int UserID = Convert.ToInt16(item["UserID"].Text);
string Description = "Monthly Storage Fee - Tag: " + item["PackageTag"].Text + Label3.Text;
Int32 AmountDue = Convert.ToInt32(item["AmtDue"].Text);

//Change only the parameters that are different between calls.
cmd.Parameters.("@UserID", UserID);
cmd.Parameters("@Description", Description);
cmd.Parameters("@AmountDue", AmountDue);

cmd.ExecuteNonQuery();
}
}
catch
{
Label4.Text = "uh oh";
}
finally
{
connection.Close();
}
}

Я бы все-таки рекомендовал использовать табличное значение параметров, если это возможно, но это должно быть более эффективным на вашей базе, если вы не смогли использовать ПВ.

1
ответ дан 28 июня 2011 в 10:06 Источник Поделиться

Сама вставить блок в порядке: его безопасным и чистым. И он во избежание SQL-инъекций.

Однако, вы должны рассмотреть вопрос о переходе ваши постоянные код от кода пользовательского интерфейса. Попробовать работать в слоях. Существует несколько шаблонов проектирования, о предмете вы должны взглянуть.

0
ответ дан 28 июня 2011 в 01:06 Источник Поделиться

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

И re: пытаюсь пакетных этих в одно обновление/вставка заявление, я думаю, что это больше проблем, чем его ценность. Я сделал это в прошлом, но он оказался очень болезненный (как правило, для реализации решения, как XML), и это не дает много преимуществ. И если вы посмотрите на более современные решения, такие как платформы, это точно, как они это реализуют.

Единственное, что вам может понадобиться, чтобы рассмотреть, если все эти записи должны быть обернуты в транзакцию (все записи должны быть обновлены/добавлены все должны быть свернуты). Если это так, то вам придется изменить его за это. А если нет, то что вы, по-моему, вполне приемлемо.

0
ответ дан 28 июня 2011 в 01:06 Источник Поделиться

Мой взгляд на это:

protected void RadButton2_Click(object sender, EventArgs e)
{

string connectionString = ConfigurationManager.ConnectionStrings["Foo"].ConnectionString;
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("INSERT INTO Billing (UserID, Type, Date, Description, Amount) VALUES (@UserID, @Type, @Date, @Description, @AmountDue)", connection);

try
{
connection.Open();

foreach (GridDataItem item in RadGrid1.SelectedItems)
{
GridDataItem item = (GridDataItem)RadGrid1.SelectedItems;
int UserID = Convert.ToInt16(item["UserID"].Text);
string Type = "D";
DateTime Date = DateTime.Now;
string Description = "Monthly Storage Fee - Tag: " + item["PackageTag"].Text + Label3.Text;
Int32 AmountDue = Convert.ToInt32(item["AmtDue"].Text);

cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@UserID", UserID);
cmd.Parameters.AddWithValue("@Type", Type);
cmd.Parameters.AddWithValue("@Date", Date);
cmd.Parameters.AddWithValue("@Description", Description);
cmd.Parameters.AddWithValue("@AmountDue", AmountDue);

cmd.ExecuteNonQuery();
}
}
catch
{
Label4.Text = "uh oh";
}

finally
{
connection.Close();
}
}

0
ответ дан 28 июня 2011 в 01:06 Источник Поделиться