Итак, в основном у нас есть опросы, которые имеют одинаковую структуру (коллекции, свойства и т. Д.), Но данные могут быть разными ... Моя идея заключается в том, чтобы хранить все в одной таблице и создать столбец, который отделяет шаблоны от ведомые.
Хорошо, вы говорите о прототипе. «Шаблон» опроса является прототипом. Ясно, что если прототип имеет точно такую же структуру, что и экземпляр на основе прототипа, было бы глупо и расточительно создавать совершенно разные таблицы для одной и той же структуры - тем более, когда вы понимаете, что это означает любое изменение в этой структуре должен отражаться в обоих наборах.
Могу ли я добавить столбец, чтобы отличить прототип / шаблон от проведенного обследования? Нет, наверное нет. Вместо этого я бы добавил еще одну таблицу с отношением один-к-одному к корневой таблице опроса. В этой таблице я бы добавил немного метаданных, которые отличают прототип от не прототипа.
По трем причинам: 1) в любой разумной системе прототипы будут составлять небольшую часть от общего числа обследований. 2) Я часто хотел бы перечислить все прототипы, например, «Мастер создания нового опроса», в котором перечислены варианты прототипов, на которых будет основан новый опрос. И 3) для хранения этого небольшого количества дополнительных данных:
create table survey_prototype (
id int not null primary key,
survey_id references survey(id) -- the regular survey table
wizard_description varchar(80)
. . . .
);
Теперь я представляю, что в опросе также есть описание, но для прототипа это описание выглядит как «ЗАМЕНИТЕ МЕНЯ, ЭТО ОПИСАНИЕ, КОТОРОЕ УВИДЕТ ПОЛЬЗОВАТЕЛЬ», но описание wizard_description - что-то вроде «Политический опрос прототипа».
Теперь, поскольку любой поиск прототипа / шаблона не имеет возможности вернуть проведенный опрос (поскольку ни один проведенный опрос не присоединяется к survey_prototype), ваш getMaster выглядит (концептуально, предположительно, вы используете ORM) следующим образом:
ConductedSurvey : Survey {
//gets the master according to the name
GetMaster() { "select * from survey_prototype join survey..."
}
Важно: опрос имеет много связей с другими классами. Если мы решили подкласс. Должны ли все они быть разделены на подклассы (потому что мы скопировали бы данные из master для каждого объекта)?
Вы правы: для любого прототипа, который вы извлекаете через ORM, вам нужно будет его глубоко скопировать, чтобы сохранить новый опрос, а не перезаписывать прототип. Так как вам все равно придется делать глубокую копию, в глубокой копии вы можете вместо копирования базового класса, используемого прототипом, сделать копию подкласса.
Конечно, вам придется принимать это решение на каждом уровне иерархии; было бы неплохо инкапсулировать каждую политику преобразования для преобразования с глубоким копированием в один класс. Шаблон посетителя сделает это, так как он имеет одну перегруженную функцию visit
для (базового) класса ваших типов: так (по крайней мере) visitSurvey
, visitQuestion
, visitAnswer
.
Поскольку вы будете иметь дело с деревом (укорененным в опросе, с вопросами о детях и ответами внуков, т. Е. С композитным шаблоном), я предлагаю вам использовать шаблон посетителя в своей копии / преобразователе. Поскольку ваши занятия относительно стабильны, посетитель будет работать хорошо. И это позволяет вам иметь несколько разных конкретных посетителей, по одному для каждого типа преобразования (и когда приходит время отображать или оценивать опрос, вы также можете написать посетителя для этого - так что вы получите эту функциональность почти "для бесплатно "после настройки шаблона посетителя).
Для обработки подклассов в базе данных вы можете использовать для этого любой из распространенных шаблонов nhibernate; таким образом, после того как вы посетили и преобразовали, у вас будет новое непрототипное дерево опросов, которое может быть автоматически сохранено в базе данных с помощью nhibernate.
Итак, подведем итоги: таблица survey_prototype, получите прототип, nhibernate извлечет все дерево, когда вы запросите корень в survey_prototype, посетите это дерево с преобразователем глубокого копирования, который возвращает скопированный корень, и пусть пользователь напишет об этом , сохраните скопированный корень и пусть nhibernate рекурсивно сохранит каждый узел дерева. Когда пользователь должен увидеть опрос, не относящийся к прототипу, извлеките корень из опроса с помощью nhibernate, используйте экранный посетитель для его отображения и т. Д.