Вопрос по c#, asp.net, sql-server – Поскольку нет никакого параметра массива Sqlserver, каков наилучший способ продолжить?

4

Мне нужно создать несколько записей в sqlserver, каждая с одинаковым значением в столбце A, но с уникальным значением в столбце B. У меня есть значения для столбца B в массиве.

Я использую VS2008, aspnet, c # 3.5, sqlserver 2005.

Мне лучше

Опция 1.

Сделаете 1 вызов хранимой процедуры в sqlserver из кода C #, а затем выполните всю работу по обработке хранимой процедуры в tsql?

Это будет включать объединение всех значений в массиве c # в одну строку с разделителями-запятыми и передачу строки в tsql в качестве параметра, затем зацикливание и разбиение строки на отдельные значения и вставку записи для каждого из них, все в рамках хранимой процедуры.

Из того, что я вижу, это может потребовать простого отката в случае необходимости, но очень неуклюжей обработки строк в tsql.

Или же

Вариант 2

Выполнение цикла в c # и передача данных в виде sqlparams из c # одной записи за раз в сохраненный процесс для вставки каждой записи.

То есть foreach (int, ключ в myarray) & # x2026; вставить запись

Я мог бы сделать этот код во сне, но как бы я мог откатить, если что-то произошло в середине обработки? И я должен сделать цикл внутри в одном connection.open и connection.close?

У кого-нибудь есть другие варианты сделать это?

Ваш Ответ

5   ответов
1

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

using (SqlConnection connection = new SqlConnection(connectionstring)) {
   connection.Open();

   string sql = "CREATE TABLE #foo (myvalue [INT]) ";
   using (SqlCommand command = connection.CreateCommand()) {
      command.CommandText = sql;
      command.CommandType = CommandType.Text;

      command.ExecuteNonQuery(); // create the temp table

      foreach (int value in myValuesList) {
         command.CommandText = "INSERT INTO #foo ([myvalue]) VALUES (" + value + ") ";

         command.ExecuteNonQuery();
      }

      command.CommandType = CommandType.StoredProcedure;
      command.CommandText = "StoredProcThatUsesFoo";

      // fill in any other parameters

      command.ExecuteNonQuery();
   }
}
+1 моя мысль точно - обновить до SQL Server 2008 и покончить с этой проблемой раз и навсегда! :-)
1

остороннюю передачу, вариант 2 не использует обработку строки хоккейной строки), но я, скорее всего, в конечном итоге перейду к варианту 2. Вариант 1 страдает от ограничений размераvarchars (8000, если вы не используетеvarchar(MAX); Я понятия не имею, что будет за запятаяvarchar(MAX) Строка, которая очень длинная).

Что касается отката, да, просто выполните все операции на одном открытом соединении и используйтеSqlTransaction объект.

Например...

using(SqlConnection conn = new SqlConnection("connection string"))
{
    conn.Open();

    using(SqlTransaction trans = conn.BeginTrasnaction())
    {
        try
        {
            using(SqlCommand cmd = new SqlCommand("command text", conn, trans))
            {
                SqlParameter aParam = new SqlParameter("a", SqlDbType.Int);
                SqlParameter bParam = new SqlParameter("b", SqlDbType.Int);

                cmd.Parameters.Add(aParam);
                cmd.Parameters.Add(bParam);

                aParam.Value = 1;

                foreach(int value in bValues)
                {
                    bValue = value;

                    cmd.ExecuteNonQuery();
                }
            }

            trans.Commit();
        }
        catch
        {
            trans.Rollback();

            throw; // so the exception can propogate up
        }
    }
}
+1 Я бы тоже использовал вариант 2.
@Jab: Спасибо, но ты на самом деле не +1 мне;)
Это начало становиться дорогим, если массив "B" (как уже упоминалось в вопросе) очень большой. -Я не знаю лучшего решения, но это, вероятно, что-то, что нужно иметь в виду.
7
Статья Эрланда уже много лет является темой по этой теме, и ее обязательно нужно прочитать, если вы решитесь на это.
real простой ответ будет: обновить до SQL Server 2008 и использовать табличные параметры :-)
Я как бы надеялся на легкий ответ. Ну что ж. Спасибо за ссылку. Lill Lansey
1

ansactionScope. Это позволит вам свернуть несколько вызовов сохраненного процесса в транзакцию с возможностью отката. Другим вариантом будет то, что вы можете передать свой массив в виде XML, а в хранимом процессе вы можете уничтожить этот XML во временной таблице для использования в вашем процессе.

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

+1 моя мысль точно - обновить до SQL Server 2008 и покончить с этой проблемой раз и навсегда! :-)
2

передать массив в виде строки с разделителями. Я имел обыкновение делать это в дни до sql2005 в связи с этимФункция разделения TSQL, Я бы передал массив, используя & quot; | & quot; в качестве разделителя.

Сейчас я сериализирую массив в XML, а затем вставляю содержимое в переменную таблицы для обработки с использованиемsp_xml_preparedocument хранимая процедура.

Я бы не использовал вариант 2, так как он делает несколько обращений к базе данных.

+1 - я использовал функцию split для передачи массивов в мои хранимые процедуры. Хотя я не могу дождаться обновления до SQL2008 и использовать вместо него XML.
что функция разбиения цикла является медленной, используйте метод таблицы чисел из:sommarskog.se/arrays-in-sql-2005.html#tblnum
Передача строки с разделителями может быть затруднительной, если верхний предел размера строки не может быть легко определен.
Вы все еще используете sp_xml_preparedocument в SQL Server 2005? Когда он поддерживает XQuery и т. Д.?
sp_xml_preparedocument доступен в SQL 2005, а также в 2008 году.

Похожие вопросы