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