Заводской шаблон для разных типов пользователей, сохраненных в базе данных - PullRequest
1 голос
/ 04 марта 2011

У меня есть вопрос, на который нужно ответить несколько раз, но я не могу найти ни одного хорошего поискового слова, чтобы выяснить, как лучше всего его решить.

В моем приложении у меня будут разные типыпользователей, которые будут иметь разные свойства и разные методы, но многое из этого также будет одинаковым.Поэтому я создаю базовый класс «Пользователь» и другие классы «Игрок», «Тренер» и т. Д., Который наследуется от класса «Пользователь».

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

У меня будет только один метод входа в систему, поэтому он всегда будет возвращать базовый класс, но тогда, когда там будут использоваться различные конкретные типы ('player', 'trainer'),быть броском к этому классу.Но как я делаю вызов базы данных, чтобы заполнить мои разные классы.

Что я мог сделать, так это то, что в пользовательской таблице тип также сохраняется.Когда я получаю эту информацию обратно в свой код, я проверяю, что это за тип, а затем вызываю базу данных, получая конкретную информацию для этого типа, создаю правильный тип и возвращаю его как «пользователя» в коде.Но мне не нравится идея, что мне нужно дважды вызывать базу данных, чтобы заполнить мои объекты данными, я мог бы решить ее с помощью SP, но я стараюсь не использовать SP.

Есть ли хорошийспособ решить эту проблему одним вызовом базы данных, когда я не знаю, какой тип будет возвращен при вызове базы данных.

Спасибо за любую помощь.

Ответы [ 2 ]

1 голос
/ 04 марта 2011

Прежде всего, на мой взгляд, я бы хотел предложить вам не думать о реляционном дизайне, основанном на объектно-ориентированном программном решении.

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

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

Имея это, вы создадите реляционную таблицу под названием "TrainerUsersProfiles", "PlayerUsersProfiles" и т. Д.

Фактически, «TrainerUsersProfiles», «PlayerUsersProfiles» - это что-то вроде данных профиля, потому что вы должны быть пользователем, чтобы проходить аутентификацию и быть авторизованными для ресурсов приложения. Но пользователь может иметь больше связанной информации, скажем, «профиль». Любая информация в качестве тренера или игрока является частью профиля пользователя.

Теперь пришло время узнать, какие атрибуты являются общими для тренеров и игроков (и любых других). Такие общие атрибуты должны быть в таблице профиля пользователя «UsersProfiles», которая имеет отношение один к одному с конкретным пользователем.

Например, я бы поместил любые расширенные данные профиля в «TrainerUsersProfiles» и «PlayerUsersProfiles», и оба (или более) будут иметь отношение один к одному с некоторым профилем пользователя.

Подведение итогов: у пользователя есть профиль, а в профиле - расширенные специализированные данные профиля.

Говоря об объектно-ориентированном слое - приложении - я хотел бы предложить, что лучше избегать этой абстрактной фабрики и просто использовать репозиторий:

userRepository.GetById([id])

Пользовательский класс будет иметь свойство "Kind", которое является перечислением видов профиля пользователя (Trainer, Player и т. Д.).

Кроме того, класс User будет иметь свойство "Profile", которое также должно иметь свойство "Properties". «Свойства» относятся к типу, называемому «ProfileProperties», и есть «TrainerProperties» и «PlayerProperties», получающие его.

Наконец, это будет пример использования:

User someUser = userRepository.GetById([id]);
string somePropertyValue = null;

switch(someUser.Kind)
{
    case Trainer:
            somePropertyValue = ((TrainerProperties)someUser.Profile.Properties).SomeTrainerProperty;
            break;
    case Player:
            somePropertyValue = ((PlayerProperties)someUser.Profile.Properties).SomePlayerProperty;
            break;
}

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

1 голос
/ 04 марта 2011

Это называется "Полиморфная стойкость". Есть разные способы сделать это. Общим для всех них является то, что в базовой таблице есть столбец, который содержит реальный класс объекта в каждой строке.

Картограф OR использует этот столбец либо для загрузки большего числа столбцов той же таблицы, либо для объединения столбцов в других таблицах.

Подробнее см. В документах Hibernate . Вот пример из Java Tips .

...