开发者

Cannot insert duplicate key in object (GetReparentedValue / hierarchyid)

Using examples I found on the web I have created a function which reparents children using the GetReparentedValue.

However when I have ran the code I get the following error: Cannot insert duplicate key in object.

I understand why (because I am trying to reparent the children and the new parent already has children so I need to know the MAX path (hierarchyid) of the child wit开发者_Go百科hin the new parent structure, but I don't understand how I'm actually going to do that.

path 0x58

oldPath 0x

new path 0x68

SqlCommand command = new SqlCommand("UPDATE Structure SET " +
                                    "Path = " + path + ".GetReparentedValue" +
                                    "(" +
                                      oldPath + ", " + newPath +
                                    ")" +
                                    "ParentID = @id " +
                                    "WHERE Path = " + path, _connection);

I have to do this when adding a child so I thought it would need to add this somewhere to the query above but I dont know where path + ".GetDescendant(" + lastChildPath + ", NULL)

Database Table

StructureID   int                         Unchecked  
Path          hierarchyid                 Unchecked  
PathLevel     ([Path].[GetLevel]())       Checked  
Description   nvarchar(50)                Checked  
ParentID      int                         Checked  
ParentPath    ([Path].[GetAncestor]((1))) Checked  

Anyone have any suggestion?

Thanks in advance for any help :-)

Clare


There are a couple of changes you can make to get this to work. First, you don't need the oldPath that represents the parent of the node that you want to move. In the .GetReparentedValue function, you put the hierarchyid of the node that is moving, which is the value in path.

The second change is to add another SELECT statement to apply your GetDescendant function. Here's a sample script that you can try in SQL Server Management Studio (SSMS), or alter to incorporate into your SQLCommand calls. The first few lines (variable declarations are assignments) are only for running in SSMS. You would transfer the last SELECT and the UPDATE statements to the calling code.

DECLARE @Path hierarchyid
DECLARE @oldPath hierarchyid
DECLARE @newPath hierarchyid
SELECT @Path=0x58, @oldPath=0x, @newPath=0x68

SELECT @newPath = @newPath.GetDescendant(MAX(Path), NULL)
FROM Structure
WHERE path.GetAncestor(1)=@newPath;

UPDATE Structure
SET Path = Path.GetReparentedValue(@Path, @newPath)
WHERE Path = @Path;

Your UPDATE statement and this revision will only re-parent a single node. It will not automatically move the children of the moving node. Children of the moving-node will be orphaned.

If you need to move the selected node and all descendants of the node, you can use the following variation of the previous statements.

DECLARE @Path hierarchyid
DECLARE @oldPath hierarchyid
DECLARE @newPath hierarchyid
SELECT @Path=0x58, @oldPath=0x, @newPath=0x68

SELECT @newPath = @newPath.GetDescendant(MAX(Path), NULL)
FROM Structure
WHERE Path.GetAncestor(1) = @newPath ;

UPDATE Structure
SET Path = Path.GetReparentedValue(@Path, @newPath)
WHERE Path.IsDescendantOf(@Path) = 1;

Actually, the only change from the first script to this script is in the very last line. The Path.IsDescendantOf(@Path) = 1 test is true for all descendants of @Path, including @Path. The hierarchical relationships will be maintained after the update.


This is another example of moving a subtree and all of it's children. It is essentially the same as the accepted answer. This is taken from the Docs:

CREATE PROCEDURE MoveOrg(@oldMgr nvarchar(256), @newMgr nvarchar(256) )  
AS  
BEGIN  
DECLARE @nold hierarchyid, @nnew hierarchyid  
SELECT @nold = OrgNode FROM HumanResources.EmployeeDemo WHERE LoginID = @oldMgr ;  

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE  
BEGIN TRANSACTION  
SELECT @nnew = OrgNode FROM HumanResources.EmployeeDemo WHERE LoginID = @newMgr ;  

SELECT @nnew = @nnew.GetDescendant(max(OrgNode), NULL)   
FROM HumanResources.EmployeeDemo WHERE OrgNode.GetAncestor(1)=@nnew ;  

UPDATE HumanResources.EmployeeDemo    
SET OrgNode = OrgNode.GetReparentedValue(@nold, @nnew)  
WHERE OrgNode.IsDescendantOf(@nold) = 1 ;  

COMMIT TRANSACTION  
END ;  
GO
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜