Как получить вывод из команды вставки SQL Server с более чем одной строкой, используя С# ADO.Net?

Я хочу получить весь выходной первичный ключ из этой команды вставки, используя С# ADO.Net.

Я запускаю это в SQL Server 2012 Studio и вижу таблицу результатов со всеми значениями, так можно ли получить эту таблицу из С#?

INSERT INTO dbo.Suspension 
(pallet_position, processing_pallet_pkey, datetime_created, datetime_updated,
created_by, updated_by) 
OUTPUT INSERTED.pkey VALUES
(1, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(2, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(3, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(4, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2);

Что я пробовал в С# ADO.NET. Но DataTable не получил никакого значения из insertedOutput.

SqlCommand cmd = new SqlCommand(insertQuery, this.conn);
var insertedOutput = cmd.ExecuteReader(); 

DataTable dt = new DataTable();
dt.Load(insertedOutput); // something wrong here

Заметил, что я скопировал код SQL из отладчика. Это работает нормально. (не уверен, откуда взялось «это», но это не вызвало никаких проблем)

В отладчике есть результаты cmd.ExecuteReader() во вставленном выводе, но я не могу скопировать эти результаты из dt (переменная DataTable).


person gentlerainsky    schedule 13.10.2014    source источник
comment
// this cause an error. ‹=== что говорит ошибка?   -  person Marc Gravell    schedule 13.10.2014
comment
Извините, я неправильно разместил комментарий об ошибке. кажется, что dt.Load не получает значение из InsertOutput. (но без ошибки компиляции)   -  person gentlerainsky    schedule 13.10.2014
comment
этот оператор sql даже не выглядит законным (this.created_by и т. д.) - можете ли вы подтвердить, что там происходит?   -  person Marc Gravell    schedule 13.10.2014
comment
Да, я пробовал это в SQL Server Management Studio. Теперь основная проблема в том, что я не могу получить значение из dt.Load(insertedOutput).   -  person gentlerainsky    schedule 13.10.2014


Ответы (2)


Ваш запрос выглядит нормально (за исключением this.created_by/this.updated_by, что меня смущает, но... если вы говорите, что это работает...)

Поэтому моя первоначальная мысль такова: возможно, у вас есть триггер вместо того, который неправильно обрабатывает только одну строку? Хотя я ожидал, что сообщу:

Целевая таблица 'dbo.Suspension' оператора DML не может иметь никаких включенных триггеров, если оператор содержит предложение OUTPUT без предложения INTO.

Следующие 3 способа чтения этого sql (или очень похожей на него версии) работают нормально:

using (var conn = new SqlConnection(connectionString))
{
    conn.Open();
    const string insertQuery = @"
INSERT INTO dbo.Suspension
(pallet_position, processing_pallet_pkey, datetime_created, datetime_updated,
[this.created_by], [this.updated_by]) 
OUTPUT INSERTED.pkey VALUES
(1, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(2, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(3, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(4, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2);";

    // via datatable
    DataTable dt = new DataTable();
    using (SqlCommand cmd = new SqlCommand(insertQuery, conn))
    using (var insertedOutput = cmd.ExecuteReader())
    {
        dt.Load(insertedOutput);
    }
    Console.WriteLine(dt.Rows.Count); // 4

    // via manual read
    var list = new List<int>();
    using (SqlCommand cmd = new SqlCommand(insertQuery, conn))
    using (var insertedOutput = cmd.ExecuteReader())
    {
        while(insertedOutput.Read())
        {
            list.Add(insertedOutput.GetInt32(0));
        }
    }
    Console.WriteLine(list.Count); // 4

    // via dapper
    var ids = conn.Query<int>(insertQuery).ToList();
    Console.WriteLine(ids.Count); // 4
}
person Marc Gravell    schedule 13.10.2014
comment
Для полноты мой сценарий создания: create table Suspension (pkey int not null identity(1,1), pallet_position int, processing_pallet_pkey int, datetime_created datetime, datetime_updated datetime, [this.created_by] int, [this.updated_by] int); - person Marc Gravell; 13.10.2014
comment
Спасибо за ваши деньги, теперь это работает с DataTable, я не очень понимаю, почему это не работало вчера. Из всех трех способов, не могли бы вы сказать мне, какой из них рекомендуется. В качестве одного из удаленных ответов в этом посте, который я не знаю, кто его опубликовал, говорится, что это (DataTable) не лучший способ. - person gentlerainsky; 14.10.2014
comment
@gentlerainsky удаленный ответ на самом деле был написан мной, но он был основан на неправильном понимании вопроса. Так что я повторю свое предыдущее мнение, что DataTable не лучший способ прочитать несколько целых чисел (на самом деле, я вообще редко использую DataTable). Код для ручного чтения достаточно прост, но в конечном итоге вам придется написать много всего — вот почему я написал dapper — бесплатно доступный высокопроизводительный инструмент для доступа к данным; как и в последнем примере, все это становится одной строкой. Так что да, я бы использовал это; p nuget.org/packages/Dapper - person Marc Gravell; 14.10.2014

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

DECLARE @tblIds TABLE (id int)

Insert into dbo.Suspension 
(pallet_position, processing_pallet_pkey, datetime_created, datetime_updated,
created_by, updated_by)
OUTPUT inserted.pkey INTO @tblIds
values
(1, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(2, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(3, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), 
(4, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2)

select * from @tblIds

Здесь я предполагаю, что pkey - это ваш столбец идентификаторов :)

person Satyajit    schedule 13.10.2014