Невозможно вставить повторяющийся ключ в объект (GetReparentedValue /ierarchyid) - PullRequest
4 голосов
/ 25 августа 2010

Используя примеры, которые я нашел в Интернете, я создал функцию, которая переопределяет детей с помощью GetReparentedValue.

Однако, когда я запустил код, я получаю следующую ошибку: Невозможно вставить дубликат ключа в объект.

Я понимаю, почему (потому что я пытаюсь переучить детей, а у нового родителя уже есть дети, поэтому мне нужно знать МАКСИМАЛЬНЫЙ путь (иерархию) дочернего элемента в структуре нового родителя, но я не понимаю, какЯ на самом деле собираюсь сделать это.

путь 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 ]

3 голосов
/ 06 ноября 2010

Есть несколько изменений, которые вы можете сделать, чтобы заставить это работать.Во-первых, вам не нужен oldPath, представляющий родителя узла, который вы хотите переместить.В функции .GetReparentedValue вы помещаете иерархию движущегося узла, которая является значением в 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.Иерархические отношения будут поддерживаться после обновления.

0 голосов
/ 19 октября 2018

Это еще один пример перемещения поддерева и всех его дочерних элементов.По сути, это то же самое, что и принятый ответ.Это взято из Документов :

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