Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 HierarchyID: генерация ид для вставки узла  [new]
Winnipuh
Member [заблокирован]

Откуда: Київ
Сообщений: 10428
Получается, что добавление узла к одному и тому же паренту в разных транзакциях с использованием вызова

GetDescendant(ch1, ch2)


дает один и тот же ид, и следовательно можно получить проблему во время (после вставки) узла?
Как обрабатывать такой случай?

Или я ошибаюсь?
31 июл 13, 19:21    [14644971]     Ответить | Цитировать Сообщить модератору
 Re: HierarchyID: генерация ид для вставки узла  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Winnipuh
Как обрабатывать случай, когда генерируемые данные сильно пересекаются по уникальности

1. Понять и описать предметную область, чтоб понять почему это возникло
2. Понять, в чём ошибка:
а) в неправильной постановке бизнес процессов (к примеру: одновременно более одного ответственного лица за сущность)
б) в неправильной структурной реализации (ошибки схемы бд)
в) в неправильной реализации операции
3. Устранить

Начнём неправильно, с самого неважного пункта - 2.в)
Но большинство ошибок возникают на верхнем уровне, устраняя первоначальную проблему полностью.

Надо понять главное дерево - это единая сущность. И когда вы делаете изменение вы затрагиваете очень много элементов в нём.
Нельзя в данный момент изменять ни Child1, ни Child2, ни всех их родительских узлов. И главное что пространство между ними должно быть пусто с намерением изменить (U).

Тут нужно понять главное что выбор/поиск Child1 и Child2 неотрывно от процесса изменения.

Если вы это разрываете, то тогда первоначально задача изменяется - вставляем если пусто, иначе выбрасывание исключения.
+ Это элементарный случай.
USE tempdb
CREATE TABLE dbo.Tree (HID HierarchyID PRIMARY KEY);
INSERT dbo.Tree VALUES
 (HierarchyID::Parse(N'/'))
,(HierarchyID::Parse(N'/1/'))
,(HierarchyID::Parse(N'/1/1/'))
,(HierarchyID::Parse(N'/1/2/'))
,(HierarchyID::Parse(N'/2/'))
GO
USE tempdb
DECLARE	 @Child1 HierarchyID = HierarchyID::Parse(N'/1/1/')
	,@Child2 HierarchyID = HierarchyID::Parse(N'/1/2/')
BEGIN TRAN XTreeIns

INSERT	dbo.Tree (HID)
SELECT	@Child1.GetAncestor(1).GetDescendant(@Child1,@Child2)
WHERE	NOT Exists(
	SELECT	*
	FROM	dbo.Tree With(UpdLock)
	WHERE	HID > @Child1
	AND	HID < @Child2)

IF (@@RowCount != 1) BEGIN
	DECLARE	 @Child1S NVarChar(256) = @Child1.ToString()
		,@Child2S NVarChar(256) = @Child2.ToString()
	RAISERROR(N'Между элементами "%s" и "%s" уже существуют узлы',18,1,@Child1S,@Child2S)
	ROLLBACK
	RETURN
END
-- COMMIT TRAN XTreeIns
-- ROLLBACK
GO
SELECT HID.ToString() FROM dbo.Tree
-- DROP TABLE dbo.Tree;

Если процесс неразрывный, тогда надо описать принцип выбора Child1 и Child2 и плясать от него.
К примеру вариант "добавляем в конец".
+ Случай также элементарный.
USE tempdb
CREATE TABLE dbo.Tree (HID HierarchyID PRIMARY KEY);
INSERT dbo.Tree VALUES
 (HierarchyID::Parse(N'/'))
,(HierarchyID::Parse(N'/1/'))
,(HierarchyID::Parse(N'/1/1/'))
,(HierarchyID::Parse(N'/1/2/'))
,(HierarchyID::Parse(N'/2/'))
GO
USE tempdb
DECLARE	@Parent HierarchyID = HierarchyID::Parse(N'/1/')
BEGIN TRAN XTreeIns

INSERT	dbo.Tree (HID)
SELECT	Top(1) @Parent.GetDescendant(LastChild.HID,NULL)
FROM	dbo.Tree AS LastChild WITH(UpdLock)
WHERE	HID < @Parent.GetAncestor(1).GetDescendant(@Parent,NULL)
ORDER BY HID DESC

-- COMMIT TRAN XTreeIns
-- ROLLBACK
GO
SELECT HID.ToString() FROM dbo.Tree
-- DROP TABLE dbo.Tree;
Остальное по аналогии, по тому же принципу: описываем что изменяется всё что между элементами.
Т.е. запрос с намерением.

И в принципе неважно, вставляете вы один элемент или скопом.

На самом деле у варианта {ID,ParentID,Order} нужно делать тоже самое. Иначе будет исключение по ключу {ParentID,Order}.

И вообще любые задачи по относительной вставке, т.е. вставка с ключём - делается так же.
В случае использования уникального генератора (SEQUENCE, GUID, Identity) сводится к малой вероятности пересечения и стратегии выбрасывания в исключение.
1 авг 13, 02:10    [14646240]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить