Отправка DataTable в качестве параметра хранимой процедуре

Я пытаюсь отправить DataTable в хранимую процедуру, используя С#, .net 2.0 и SQLServer 2012 Express.

Примерно так делаю:

        //define the DataTable
        var accountIdTable = new DataTable("[dbo].[TypeAccountIdTable]");

        //define the column
        var dataColumn = new DataColumn {ColumnName = "[ID]", DataType = typeof (Guid)};

        //add column to dataTable
        accountIdTable.Columns.Add(dataColumn);

        //feed it with the unique contact ids
        foreach (var uniqueId in uniqueIds)
        {
            accountIdTable.Rows.Add(uniqueId);
        }

        using (var sqlCmd = new SqlCommand())
        {
            //define command details
            sqlCmd.CommandType = CommandType.StoredProcedure;
            sqlCmd.CommandText = "[dbo].[msp_Get_Many_Profiles]";
            sqlCmd.Connection = dbConn; //an open database connection

            //define parameter
            var sqlParam = new SqlParameter();
            sqlParam.ParameterName = "@tvp_account_id_list";
            sqlParam.SqlDbType = SqlDbType.Structured;
            sqlParam.Value = accountIdTable;

            //add parameter to command
            sqlCmd.Parameters.Add(sqlParam);

            //execute procedure
            rResult = sqlCmd.ExecuteReader();

            //print results
            while (rResult.Read())
            {
                PrintRowData(rResult);
            }
        }

Но затем я получаю следующую ошибку:

ArgumentOutOfRangeException: No mapping exists from SqlDbType Structured to a known DbType.
Parameter name: SqlDbType

При дальнейшем изучении (в MSDN, SO и других местах) выясняется, что .net 2.0 не поддерживает отправку DataTable в базу данных (отсутствуют такие вещи, как SqlParameter.TypeName), но я все еще не уверен, так как никого не видел явно заявляя, что эта функция недоступна в .net 2.0

Это правда?

Если да, есть ли другой способ отправить набор данных в базу данных?

Заранее спасибо!


person Asaf Sitner    schedule 01.01.2013    source источник
comment
Я считаю, что параметры табличных значений были добавлены в SQL Server 2008, поэтому они, вероятно, недоступны в .NET 2.0. Не могли бы вы вместо этого отправить XML и разобрать его из хранимой процедуры в табличную переменную?   -  person lc.    schedule 01.01.2013
comment
@лк. - Мог бы, но далеко не оптимально. :(   -  person Asaf Sitner    schedule 01.01.2013
comment
Согласен с тем, что это далеко не оптимально, я просто пытаюсь немного мыслить нестандартно. В вашем случае кажется, что вы пытаетесь отправить кучу идентификаторов GUID, и, поскольку они имеют фиксированный размер, вы даже можете просто выровнять их от начала до конца в varbinary, а затем разделить их обратно в табличную переменную. в цикле процедуры. Не оптимально для чего-то более сложного, но здесь может сработать.   -  person lc.    schedule 01.01.2013


Ответы (2)


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

Если я понимаю, что вы хотите сделать — быстро загрузить содержимое DataTable в предопределенную реальную таблицу с той же структурой, я предлагаю вам исследовать SQLBulkCopy.

Из документации:

Microsoft SQL Server включает в себя популярную утилиту командной строки под названием bcp для перемещения данных из одной таблицы в другую как на одном сервере, так и между серверами. Класс SqlBulkCopy позволяет создавать решения с управляемым кодом, предоставляющие аналогичные функции. Существуют и другие способы загрузки данных в таблицу SQL Server (например, операторы INSERT), но SqlBulkCopy предлагает значительное преимущество в производительности по сравнению с ними.

Класс SqlBulkCopy можно использовать для записи данных только в таблицы SQL Server. Однако источник данных не ограничивается SQL Server; можно использовать любой источник данных, если данные можно загрузить в экземпляр DataTable или прочитать с помощью экземпляра IDataReader.

SqlBulkCopy завершится ошибкой при массовой загрузке столбца DataTable типа SqlDateTime в столбец SQL Server, тип которого является одним из типов даты/времени, добавленных в SQL Server 2008.

Однако вы можете определить параметры значений таблицы в SQL Server в более поздних версиях и использовать их для отправки таблицы (DateTable) в методе, который вы запрашиваете. Пример приведен по адресу http://sqlwithmanoj.wordpress.com/2012/09/10/passing-multipledynamic-values-to-stored-procedures-functions-part4-by-using-tvp/

person David    schedule 01.01.2013
comment
Я создал тип, но не могу отправить DataTable из С#. - person Asaf Sitner; 02.01.2013
comment
Что ж, мне удалось быть умнее на стороне БД и добиться желаемого эффекта без отправки DataTable. По-видимому, с .net 2 это невозможно, что досадно, но это жизнь. Все равно, спасибо за помощь! - person Asaf Sitner; 02.01.2013

По моему опыту, если вы можете скомпилировать код на C#, это означает, что ADO.Net поддерживает этот тип. Но если при выполнении кода произойдет сбой, целевая база данных может его не поддерживать. В вашем случае вы упоминаете [Sql Server 2012 Express], поэтому он может его не поддерживать. Насколько я понимаю, тип таблицы поддерживался с [Sql Server 2005], но вам нужно было поддерживать режим совместимости базы данных выше 99 или что-то в этом роде. Я на 100% уверен, что это будет работать в 2008 году, потому что я использовал его и широко использовал для массовых обновлений через хранимые процедуры, используя [Определяемые пользователем типы таблиц] (также известный как UDTT) в качестве входного параметра. для хранимой процедуры. Опять же, вы должны поддерживать совместимость базы данных выше 99, чтобы использовать команду MERGE для массовых обновлений.

И, конечно, вы можете использовать SQLBulkCopy, но не уверены, насколько он надежен, зависит от

person Vincy    schedule 02.02.2015