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

发布于 2024-09-15 21:35:58 字数 1215 浏览 13 评论 0原文

使用我在网上找到的示例,我创建了一个函数,该函数使用 GetReparentedValue 重新设置子级的父级。

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

我明白为什么(因为我试图重新设置孩子的父级,而新的父级已经有了孩子,所以我需要知道新父级结构中子级的最大路径(hierarchyid),但我不明白我实际上是如何 我必须在添加子项时执行

路径 0x58

oldPath 0x

新路径 0x68

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

此操作,因此我认为需要将其添加到上面的查询中,但我不知道路径 + ".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  

有人有任何建议吗?

提前感谢您的帮助:-)

Clare

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 within 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浊酒尽余欢 2024-09-22 21:35:58

您可以进行一些更改来使其发挥作用。首先,您不需要表示要移动的节点的父节点的 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)均成立。更新后仍将保留层级关系。

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.

伴我心暖 2024-09-22 21:35:58

这是移动子树及其所有子树的另一个示例。它本质上与接受的答案相同。这取自 文档

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文