2016-11-16 2 views
0

У меня есть довольно сложный объект, содержащий вложенные списки элементов, каждый из которых имеет свою собственную таблицу.Получить SCOPE_IDENTITY mid-transaction

При создании этого объекта я хотел бы вставить его вместе с его дочерними элементами и всеми их потомками в одну транзакцию по причине производительности.

мои таблицы:

Parent 
|Id| Has a list of child 

Child 
|Id|ParentId| Has a list of Grandchild 

Grandchild 
|Id|ChildId| 

Вот что моя сделка будет выглядеть следующим образом:

INSERT INTO Parent(mycolumns) VALUES (mydata);SELECT SCOPE_IDENTITY() into @ParentId; 

--insert the first child and his grandchilds 
INSERT INTO Child(mycolumns, parentid) VALUES (mydata, @ParentId);SELECT SCOPE_IDENTITY() into @ChildId; 
INSERT into Grandchild(mycolumns, childid) VALUES (mydata, @ChildId); 
INSERT into Grandchild(mycolumns, childid) VALUES (mydata, @ChildId); 
... loop through all grandchilds with this childid 

--insert the second child and his grandchilds 
INSERT INTO Child(mycolumns, parentid) VALUES (mydata, @ParentId);SELECT SCOPE_IDENTITY() into @ChildId; 
INSERT into Grandchild(mycolumns, childid) VALUES (mydata, @ChildId); 
INSERT into Grandchild(mycolumns, childid) VALUES (mydata, @ChildId); 
... loop through all grandchild with this childid again... 

То, как я сделать это, сохраняя все свои запросы в «операции» объект, а затем пересекая их в транзакцию.

using (SqlConnection connection = new SqlConnection(this.ConnectionString)) 
     { 
      connection.Open(); 
      using (SqlTransaction transaction = connection.BeginTransaction()) 
      { 
       foreach (var operation in operations) 
       { 
        using (SqlCommand command = new SqlCommand(operation.SqlCommand, connection, transaction)) 
        { 
         if (operation.Parameters != null) 
         { 
          foreach (var param in operation.Parameters) 
          { 
           command.Parameters.AddWithValue(param.Name, param.Value); 
          } 
         } 
         command.ExecuteNonQuery(); 
        } 
       } 
       transaction.Commit(); 
      } 
     } 

моя проблема я не могу показаться, чтобы найти способ сохранить выбор SCOPE_IDENTITY() в переменную (что-то похожее на это: «SELECT SCOPE_IDENTITY() в @ChildId;») для использования в последующей команде (но в той же транзакции).

+0

Быстрое сканирование..Modify 'command.ExecuteNonQuery();' затем объявить и использовать 'insertId = (int) command.ExecuteScalar();' для получения нового идентификатора, который вам нужно передать как 'parameter' для следующей операции. – Searching

+0

Совсем другой вариант - вставить все строки для одного поколения в один «INSERT» с помощью ['OUTPUT'] (https://msdn.microsoft.com/en-us/library/ ms177564.aspx), чтобы получить значения столбца идентификатора для вновь вставленных строк (и другого уникального столбца) во временную таблицу. ('OUTPUT' может использоваться с' INSERT', 'UPDATE',' DELETE' и 'MERGE' и обеспечивает доступ к значениям _before_ и _after_ в случае' UPDATE'.) Повторите для каждого поколения, присоединяясь к новым строкам с предками по уникальной ценности. Сложите все это в одну команду и дайте базе данных обработать все остальное. – HABO

+0

Я закончил тем, что сказал @Searching. Я создал другой метод, который заменил отсутствующие значения parentid/childid в моих запросах после выполнения команды. ExecuteScalar(). благодаря! – brem

ответ

0

Вместо функции SCOPE_IDENTITY вы всегда можете использовать предложение OUTPUT. Это гораздо более надежный и гибкий подход.

declare @id TABLE(id int not null); 
INSERT INTO Child(mycolumns, parentid) 
OUTPUT INSERTED.childid INTO @ID(id) 
VALUES (mydata, @ParentId); 

Добавленное преимущество заключается в том, что вы можете хранить несколько идентификаторов в переменной таблицы. Например, вы могли бы хранить ParentID рядом с ChildID:

declare @id TABLE(ParentId int not null, ChildID int not null); 
INSERT INTO Child(mycolumns, parentid) 
OUTPUT INSERTED.parentid, INSERTED.childid INTO @ID(ParentID, ChildID) 
VALUES (mydata, @ParentId); 
0

Прежде всего нет необходимости в трех таблицах, когда только одна таблица будет делать.

id parentid 
1 null 
2 1 
3 2 

В текущем scenerio, если может быть массовой вставки (более чем одна вставка), то да, вы должны использовать пункт OUTPUT.

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

Смежные вопросы