Reputation: 33
I have a rather complex object, containing nested lists of items, each of them with their own table.
When creating this object, i would like to insert it, along with it's children and all their descendants in a single transaction for performance reason.
my tables :
Parent
|Id| Has a list of child
Child
|Id|ParentId| Has a list of Grandchild
Grandchild
|Id|ChildId|
Here is what my transaction would look like :
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...
The way i do this is by storing all my Queries into a 'operation' object, and then looping through them in a transaction.
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();
}
}
my problem is i cant seem to find a way to store SELECT SCOPE_IDENTITY() into a variable (something akin to this : "SELECT SCOPE_IDENTITY() into @ChildId;") to use in a later command (but in the same transaction).
Upvotes: 2
Views: 1656
Reputation: 5094
First of all there is no need for three tables when only one table will do.
id parentid
1 null
2 1
3 2
In your current scenerio,if there can be bulk insert (more than one insert) then yes you should use OUTPUT clause.
Your complete code is not visible,though i think,you hv to return output parameter to pass it again.
Upvotes: 0
Reputation: 3067
Instead of SCOPE_IDENTITY function you can always use OUTPUT clause. This is a much more robust and flexible approach.
declare @id TABLE(id int not null);
INSERT INTO Child(mycolumns, parentid)
OUTPUT INSERTED.childid INTO @ID(id)
VALUES (mydata, @ParentId);
Added advantage is that you can store multiple IDs into a table variable. For example, you could store the ParentID next to the 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);
Upvotes: 1