2016-11-16 16 views
0

私はかなり複雑なオブジェクトを持っています。ネストされたアイテムのリストを持ち、それぞれに独自のテーブルがあります。SCOPE_IDENTITY中間トランザクションを取得

このオブジェクトを作成する際には、パフォーマンス上の理由から、子オブジェクトとすべての子孫オブジェクトを1つのトランザクション内に挿入したいと考えています。

私のテーブル:その後、私はこれを行う方法は、「操作」オブジェクトにすべての私のクエリを格納することである

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... 

、および:ここでは

Parent 
|Id| Has a list of child 

Child 
|Id|ParentId| Has a list of Grandchild 

Grandchild 
|Id|ChildId| 

が私の取引は次のようになります。トランザクションでそれらをループします。

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(); 
      } 
     } 

私の問題は、私は変数に)(SELECT SCOPE_IDENTITYを保存する方法を見つけるように見えるカントである(これに似て何か:「@ChildIdにSCOPE_IDENTITYを(SELECT);」)(後のコマンドで使用しますしかし、同じ取引で)。

+0

クイックスキャン.Modify 'command.ExecuteNonQuery();'は 'insertId =(int)command.ExecuteScalar();'を宣言して使用して、 'parameter'として渡す必要がある新しいIDを取得します。 – Searching

+0

全く別のオプションは、1つの世代のすべての行を['OUTPUT'](1つの' INSERT')に挿入することです(https://msdn.microsoft.com/en-us/library/)。 ms177564.aspx)句を使用して、新しく挿入された行(および別の一意の列)のID列値を一時表に取得します。 ( 'OUTPUT'は' INSERT'、 'UPDATE'、' DELETE'、 'MERGE'と一緒に使用でき、' UPDATE'の場合は_before_と_after_値の両方にアクセスできます。)各世代ごとに繰り返し、新しい行を結合します祖先はユニークな価値を持っています。すべてを1つのコマンドにまとめ、残りの部分をデータベースで処理させます。 – HABO

+0

@Searchingが言ったことをやってしまった。私はcommand.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); 

さらに、複数のIDをテーブル変数に格納できるという利点があります。たとえば、あなたがたchildIDに次のParentIDを保存することができます:すべての

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

まず一つだけのテーブルがどうなる3つのテーブルは必要ありません。

id parentid 
1 null 
2 1 
3 2 

現在のscenerioでは、一括挿入(複数の挿入)が可能な場合はOUTPUT句を使用する必要があります。

あなたの完全なコードは表示されませんが、私は思っていますが、出力パラメータを再度渡して再度渡すことができます。

関連する問題