Я сталкивался с этой проблемой пару раз за свою карьеру и никогда не был очень доволен решением, и мне снова представили его в проекте, который я делаю в 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 для меня?
Редактировать:
Чтобы прояснить это, решение, которое мне нужно, - это получить все семейное древо для отображения и иметь возможность добавлять и редактировать узлы в семейное древо. Я думаю, что лучшим решением было бы сделать это одним запросом в глубоком дереве. Как спроектировать схему, хранить и извлекать - вот о чем я спрашиваю?
Как вы порекомендуете хранить свойства, отличные от типа отца или матери, в одной таблице?
Я бы сохранил такие свойства в отдельной таблице с внешним ключом, связанным с таблицей Persons.
Итак, именно то, что я тогда описал в своем вопросе.
Да, и вы можете использовать отдельную таблицу для хранения таких атрибутов, как отношения (в браке, родитель и т. д.). Идея состоит в том, чтобы сначала сказать, что они личности, а затем у них особые отношения с другими людьми. Приятно то, что отдельная таблица позволяет создавать новые отношения.
Это тоже была моя идея, и я реализовал ее таким образом пару раз. Схема чистая, но производительность - отстой. Итак, как бы вы могли запросить это эффективным образом? Представьте, что у меня есть генеалогическое древо возрастом 20 поколений и шириной до 10 детей в некоторых узлах. Это превращается в ряд звонков ...
Да, как будто я собираюсь сделать это по вопросу, которому исполнилось 7 лет.





Единственная часть, на которую я могу дать адекватный ответ, - это фреймворк ORM. NHibernate действительно хорош в обработке наследования таблиц. Например, если вы сделаете свои сопоставления правильными, он сохранит сущность Person для каждой сохраненной матери или отца.
Проверить Сопоставление наследования
Знаете ли вы, эффективно ли NHibernate извлекает весь граф объектов?
Не знаю, но возможно, быстрый поиск дал мне интересные результаты, например, этот: blogs.hibernatingrhinos.com/nhibernate/archive/2008/05/14/…
Вам не нужно связывать мать и отца с человеком, вам просто нужно связать двух родителей с каждым человеком. Определите личность с атрибутом «Пол», и мужчина автоматически станет отцом, а женщина - матерью.
Я не понимаю, насколько сложен ваш конкретный случай. Если код для отца и матери не ведет себя по-разному, вам не нужны отдельные классы. Возможно, вам вообще не понадобится подклассифицировать человека.
Если вы обнаружите, что вам действительно нужен суперкласс и два подкласса, и вы хотите, чтобы диаграмма таблицы была в некоторой степени читаемой (в отличие от GUID для каждого отдельного примитивного свойства в плоской таблице), вы можете иметь данные подкласса A и подкласса B в соответствующие таблицы с внешним ключом связаны с таблицей с данными супертипа.
Если отношение Has-A зависит от подтипа, вы должны поместить его в виде столбца в соответствующую таблицу подкласса с ограничением внешнего ключа для человека.
Я что-то пропустил? Может быть, будет полезно, если вы опишете, с какими проблемами вы сталкиваетесь при реализации этого решения.
Есть ли причина, по которой вы не можете использовать одну таблицу с внешним ключом для себя?