【问题标题】:Cannot insert duplicate key in object (GetReparentedValue / hierarchyid)无法在对象中插入重复键(GetReparentedValue / hierarchyid)
【发布时间】:2010-08-25 09:01:22
【问题描述】:

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

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

我明白为什么(因为我正在尝试让孩子重新成为父母,而新父母已经有了孩子,所以我需要知道新父母结构中孩子的 MAX 路径(层次结构),但我不明白我是怎么做到的我真的会这样做。

路径 0x58

旧路径 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  

有人有什么建议吗?

在此先感谢您的帮助 :-)

克莱尔

【问题讨论】:

  • 你能展示一下你的桌子是什么样子的吗?
  • 你好罗纳德,我已经添加了表格

标签: sql-server tsql hierarchyid


【解决方案1】:

您可以进行一些更改以使其正常工作。首先,您不需要代表要移动的节点的父节点的oldPath。在.GetReparentedValue函数中,你放入了正在移动的节点的hierarchyid,也就是path中的值。

第二个更改是添加另一个 SELECT 语句来应用您的 GetDescendant 函数。这是一个示例脚本,您可以在 SQL Server Management Studio (SSMS) 中尝试,或者更改以合并到您的 SQLCommand 调用中。前几行(变量声明是赋值)仅用于在 SSMS 中运行。您可以将最后的 SELECT 和 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 = @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。更新后会保持层级关系。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-13
      • 2014-05-04
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 2015-01-06
      相关资源
      最近更新 更多