I am trying to model a simple tree structure in my database. I have a TreeNode table with the following columns:
Id (int), Name (string), ParentId (int, nullable), ChildPosition (int)
ParentId
is a FK to a parent TreeNode, and ChildPosition
is the TreeNode's position relative to its siblings:
- Parent
-- Child 1 (ChildPosition = 0)
-- Child 2 (ChildPosition = 1)
-- Child 3 (ChildPosition = 2)
I'd like to place a composite unique constraint/index on the Parent
+ ChildPosition
columns, because I don't want any two TreeNodes to have the same ChildPosition
under a particular Parent
. Simple, right?
But I have a problem. In my UI, users can drag 'n' drop children into different positions, effectively changing their ordering (ChildPosition
) on-the-fly. This can affect multiple TreeNodes. For example, if I drag Child 3 to be before Child 1, the ChildPosition
of all three nodes should be updated:
- Parent
-- Child 3 (ChildPosition = 0)
-- Child 1 (ChildPosition = 1)
-- Child 2 (ChildPosition = 2)
However, my unique constraint doesn't seem to like this. It generates the following error:
Cannot insert duplicate key row in object 'dbo.TreeNode' with unique index 'IX_TreeNode'.
I think it's because I am trying to swap the ChildPosition
of multiple records at the same time in one transaction, and the unique constraint doesn't recognize it. So how do I solve this?
I am doing this via Linq to Sql, if that is of any relevance.
EDIT: I should also mention that I've got a check constraint on the ChildPosition
column to prevent negative numbers, and I'd like to keep it if possible. :)