Ну, так как вы используете Event Sourcing Я предполагаю, что у вас есть денормализованные проекции для запросов и что вы не запрашиваете модель домена.
Это означает, что вы в настоящее время имеете денормализованную структуру, как (упрощенный):
Node (id , type, parent_id)
Когда такое событие, как NodeCreated
обрабатывается я предполагаю, что вы в настоящее время INSERT INTO Node
и при обращении с NodeDeleted
вам DELETE FROM Node
и т.д.
Это позволяет вам восстанавливать обновленные представления ваших деревьев, но не допускает временных представлений.
Для выполнения временных запросов вам потребуется структура временных таблиц. Некоторые реляционные базы данных имеют встроенную поддержку для них, например SQL Server 2016. Не беспокойтесь, если ваша БД не поддерживает это, тривиально реализовать ее.
Чтобы реализовать простую временную таблицу, вам просто нужно добавить столбцы и end_date datetime NULL
к вашему столу. Вы также можете добавить ограничение, чтобы избежать наличия более одной строки, где end_date IS NULL
по AR id.
Then where you usually:
did an INSERT you:
INSERT INTO tbl (..., start_date) VALUES (..., currentDate)
did an UPDATE you:
UPDATE tbl SET end_date = GETDATE() WHERE [update predicate] AND end_date IS NULL
INSERT INTO tbl (..., start_date) VALUES (..., currentDate)
did a DELETE you:
UPDATE tbl SET end_date = GETDATE() WHERE [delete predicate] AND end_date IS NULL
Используя этот простой подход, вы сможете запрашивать данные на любую дату.
SELECT *
FROM tbl
WHERE start_date <= someDate AND (end_date IS NULL OR end_date > someDate)
Вот an example:
CREATE TABLE Tree (
id int NOT NULL,
parent_id int NULL,
name nvarchar(50) NOT NULL,
start_date_time datetime NOT NULL,
end_date_time datetime NULL
);
GO
CREATE UNIQUE NONCLUSTERED INDEX UN_Tree_id_end_date_time
ON Tree (id, end_date_time)
WHERE end_date_time IS NULL;
INSERT INTO Tree (
id,
parent_id,
name,
start_date_time,
end_date_time
)
VALUES
(1, NULL, 'A', GETDATE(), NULL), -- node A created
(2, NULL, 'B', GETDATE(), NULL), -- node B created
(3, 1, 'A.1', GETDATE(), NULL), -- node A.1 created
(4, 2, 'A.1.1', GETDATE(), NULL); -- node A.1.1 added
-- Node A.1 renamed
UPDATE Tree
SET end_date_time = GETDATE()
WHERE id = 3 AND end_date_time IS NULL;
INSERT INTO Tree VALUES (3, 1, 'A.1_renamed', GETDATE(), NULL);
-- Node A.1.1 removed a day after
UPDATE Tree
SET end_date_time = DATEADD(d, 1, GETDATE())
WHERE id = 4 AND end_date_time IS NULL;
-- Query nodes from root A as of now using a recursive CTE
-- Note: Did not manage to declare a @asOf variable variable in SQL Fiddle
WITH data AS (
SELECT id, parent_id, name
FROM Tree
WHERE
id = 1
AND start_date_time <= GETDATE()
AND (end_date_time IS NULL OR end_date_time > GETDATE())
UNION ALL
SELECT child.id, child.parent_id, child.name
FROM data d
INNER JOIN Tree child
ON
child.parent_id = d.id
AND start_date_time <= GETDATE()
AND (end_date_time IS NULL OR end_date_time > GETDATE())
)
SELECT *
FROM data;

как построить структуру сейчас? Почему вы не можете просто получить начальное состояние и свернуть изменения? – gabba
Я этого не делаю. Я нахожусь на ранней стадии этого проекта.Просто ищите информацию. Начальное состояние? Е., но мне нужно будет принять начальное состояние событий свертки корневого узла и получить информацию о связанных узлах и сделать то же самое для них. И рекурсивный на дно, это будет стоить много времени. Специально для 1k узлов. Ну, я не знаю, может быть, моя модель просто ошибается? Если вы так думаете, скажите мне. – Dariss
Какие типы событий у вас будут? Можно ли связать некоторые типы событий со многими узлами? Вы также можете иметь много начальных состояний – gabba