Схема данных и запрос для полиморфного дерева в SQL Server

Я сталкивался с этой проблемой пару раз за свою карьеру и никогда не был очень доволен решением, и мне снова представили его в проекте, который я делаю в ASP.Net MVC, C#, SQL Server 2008:

Представьте, что у меня есть тип (класс) Person. Кроме того, у меня есть типы Мать и Отец, которые расширяют личность. Отец и Мать очень похожи: у них обоих есть свойство под названием «Children», которое представляет собой коллекцию типа Person. «Человек» может быть представлен базовым классом Person, классом Mother или классом Father. Из этого примера вы можете видеть, что у меня продолжаются отношения наследования (is-a) и ассоциации (has-a).

Я хочу построить и сохранить родословные на SQL Server, используя эти объектно-ориентированные типы. Я думаю, что хочу иметь эти 3 таблицы: «Человек», «Мать» и «Отец». Каждый объект будет иметь запись в Person и, возможно, и запись в Mother или Father, если это необходимо (с отношением FK к Person). Вдобавок мне понадобятся таблицы переходов для хранения взаимосвязей между материнской записью и любыми дочерними записями, и то же самое с отцом.

Похоже ли это на хорошую стратегию для хранения?

Как бы вы могли эффективно запросить это для глубоких и широких генеалогических деревьев?

Проблема, на которой я зацикливаюсь, - это полиморфная природа данных, возвращаемых на данный узел в дереве. Если бы это было просто дерево объектов Person, я бы использовал Рекурсивное общее табличное выражение. Но для любого данного узла могут быть возвращены 3 различных формы данных, которые я хотел бы сопоставить с одним из 3-х объектно-ориентированных типов в C#. Очевидно, что я могу выполнить рекурсию на C# или в хранимой процедуре, но я не очень доволен производительностью таких решений в прошлом. Кроме того, как мне вставлять записи естественным образом? Мне всегда приходилось вставлять в правильном порядке (Человек, затем Отец или Мать) в прошлом из-за принудительного применения отношений FK в SQL Server.

Есть ли фреймворк, который будет обрабатывать этот тип ORM для меня?

Редактировать:

Чтобы прояснить это, решение, которое мне нужно, - это получить все семейное древо для отображения и иметь возможность добавлять и редактировать узлы в семейное древо. Я думаю, что лучшим решением было бы сделать это одним запросом в глубоком дереве. Как спроектировать схему, хранить и извлекать - вот о чем я спрашиваю?

Есть ли причина, по которой вы не можете использовать одну таблицу с внешним ключом для себя?

Otávio Décio 29.12.2008 05:47

Как вы порекомендуете хранить свойства, отличные от типа отца или матери, в одной таблице?

Jason Jackson 29.12.2008 05:53

Я бы сохранил такие свойства в отдельной таблице с внешним ключом, связанным с таблицей Persons.

Otávio Décio 29.12.2008 06:01

Итак, именно то, что я тогда описал в своем вопросе.

Jason Jackson 29.12.2008 06:02

Да, и вы можете использовать отдельную таблицу для хранения таких атрибутов, как отношения (в браке, родитель и т. д.). Идея состоит в том, чтобы сначала сказать, что они личности, а затем у них особые отношения с другими людьми. Приятно то, что отдельная таблица позволяет создавать новые отношения.

Otávio Décio 29.12.2008 06:09

Это тоже была моя идея, и я реализовал ее таким образом пару раз. Схема чистая, но производительность - отстой. Итак, как бы вы могли запросить это эффективным образом? Представьте, что у меня есть генеалогическое древо возрастом 20 поколений и шириной до 10 детей в некоторых узлах. Это превращается в ряд звонков ...

Jason Jackson 29.12.2008 06:28

Да, как будто я собираюсь сделать это по вопросу, которому исполнилось 7 лет.

Otávio Décio 29.09.2015 05:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
7
1 260
3

Ответы 3

Единственная часть, на которую я могу дать адекватный ответ, - это фреймворк ORM. NHibernate действительно хорош в обработке наследования таблиц. Например, если вы сделаете свои сопоставления правильными, он сохранит сущность Person для каждой сохраненной матери или отца.

Проверить Сопоставление наследования

Знаете ли вы, эффективно ли NHibernate извлекает весь граф объектов?

Jason Jackson 29.12.2008 06:54

Не знаю, но возможно, быстрый поиск дал мне интересные результаты, например, этот: blogs.hibernatingrhinos.com/nhibernate/archive/2008/05/14/…

Diadistis 29.12.2008 07:09

Вам не нужно связывать мать и отца с человеком, вам просто нужно связать двух родителей с каждым человеком. Определите личность с атрибутом «Пол», и мужчина автоматически станет отцом, а женщина - матерью.

Я не понимаю, насколько сложен ваш конкретный случай. Если код для отца и матери не ведет себя по-разному, вам не нужны отдельные классы. Возможно, вам вообще не понадобится подклассифицировать человека.

Если вы обнаружите, что вам действительно нужен суперкласс и два подкласса, и вы хотите, чтобы диаграмма таблицы была в некоторой степени читаемой (в отличие от GUID для каждого отдельного примитивного свойства в плоской таблице), вы можете иметь данные подкласса A и подкласса B в соответствующие таблицы с внешним ключом связаны с таблицей с данными супертипа.

Если отношение Has-A зависит от подтипа, вы должны поместить его в виде столбца в соответствующую таблицу подкласса с ограничением внешнего ключа для человека.

Я что-то пропустил? Может быть, будет полезно, если вы опишете, с какими проблемами вы сталкиваетесь при реализации этого решения.

Другие вопросы по теме