无法在对象中插入重复键(GetReparentedValue / hierarchyid)

时间:2010-08-25 09:01:23

标签: sql-server tsql hierarchyid

使用我在网络上找到的示例,我创建了一个使用GetReparentedValue重新学习孩子的函数。

但是,当我运行代码时,我收到以下错误:无法在对象中插入重复键。

我理解为什么(因为我试图重新定义孩子,新父母已经有了孩子,所以我需要知道新父结构中孩子的MAX路径(hierarchyid),但我不明白我是怎么做的实际上我会这样做。

路径0x58

oldPath 0x

新路径0x68

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

添加孩子时我必须这样做,所以我认为需要在上面的查询中添加这个,但我不知道path + ".GetDescendant(" + lastChildPath + ", NULL)

数据库表

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

有人有任何建议吗?

提前感谢您的帮助: - )

克莱尔

2 个答案:

答案 0 :(得分:3)

您可以通过几项更改来实现此功能。首先,您不需要代表要移动的节点的父级的oldPath。在.GetReparentedValue函数中,放置正在移动的节点的hierarchyid,即path中的值。

第二个更改是添加另一个SELECT语句以应用GetDescendant函数。下面是一个示例脚本,您可以在SQL Server Management Studio(SSMS)中尝试,或者更改以合并到SQLCommand调用中。前几行(变量声明是赋值)仅用于在SSMS中运行。您可以将最后的SELECTUPDATE语句转移到调用代码。

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;

您的UPDATE语句和此修订版仅重新父级单个节点。它不会自动移动移动节点的子节点。移动节点的孩子将成为孤儿。

如果需要移动所选节点和节点的所有后代,可以使用以前语句的以下变体。

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;

实际上,从第一个脚本到此脚本的唯一更改是在最后一行。对于Path.IsDescendantOf(@Path) = 1的所有后代,@Path测试均属实,包括@Path。更新后将保持层次关系。

答案 1 :(得分:0)

这是另一个移动子树及其所有子代的示例。它基本上与接受的答案相同。摘自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