Magnus Gladh
Magnus Gladh

Reputation: 1927

Factory pattern for different user types saved in database

I have a question that must be answer several times before, but I can't find any good search words to find out what's the best approach to solve it.

In my application I will have different types of Users, that will have different properties and different methods, but much of it will also be the same. So I create a baseclass 'User' and the other classes 'Player', 'trainer' and so on... that inherits from the 'User' class.

How should I save this in the database, in one huge table called 'User' that has all different properties from all classes, or should my database look like my classes? I think solution 2 is better.

I will only have one login method, so it will always return the baseclass, but then when the different specific types ('player','trainer') should be use there will be a cast to that class. But how I do the database call to populate my different classes.

What I could do is that in the user-table the type is also saved. When I get that information back to my code, I check what the type is and then call to the database getting the specific information for that type, create the correct type and return it as a 'user' in the code. But I don't like the idea that I need to call twice to the database to fill my objects with data, I could solve it with a SP, but I try not to use SP's.

Is there a good way to solve this with one call to the database, when I don't know what type that will be returned when I call to database.

Thanks for any help.

Upvotes: 1

Views: 1016

Answers (2)

Matías Fidemraizer
Matías Fidemraizer

Reputation: 64943

First of all, in my opinion, I'd like to suggest you to don't think a relational design based on the object-oriented software solution on top of it.

Taking last sentence as true, my hint will be each type of entity that has something to do in the business, you'll design a data table for it.

Anyway, I find you could have another relational design. Why don't you create such "Users" table which has basic information like an unique identifier, credentials - and any other basic info you would need for user identification, authentication and authorization -?

Having this, you'd design a relational table called "TrainerUsersProfiles", "PlayerUsersProfiles" and so on.

In fact, "TrainerUsersProfiles", "PlayerUsersProfiles" is something like a profile data, because you've to be an user in order to authenticate and be authorized to application's resources. But an user can have more related information, say it a "profile". Any information as a trainer or player is part of user's profile.

Now is time to find which attributes are shared on trainers and players (and any other one). Such shared attributes should be in user's profile table "UsersProfiles" which has an one-to-one relation to an specific user.

In instance, I'd put any extended profile data in "TrainerUsersProfiles" and "PlayerUsersProfiles", and both (or more) would have a one-to-one relation to some user profile.

Summarizing: An user has a profile, and a profile has an extended, specialized profile data.

Talking about object-oriented layer - the application -, I'd like to suggest it'd better to avoid that abstract factory and just use a repository:

userRepository.GetById([id])

User class would have a "Kind" property, which is an enumeration of user profile kinds (Trainer, Player, and so on).

In addition, User class would have a "Profile" property, which should have a "Properties" property itself too. "Properties" is of a type called like "ProfileProperties" and there's a "TrainerProperties" and "PlayerProperties" deriving it.

Finally, this would be some sample usage:

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;
}

I believe this could be your right solution and it can end in a good relational and object-oriented design.

Upvotes: 1

Aaron Digulla
Aaron Digulla

Reputation: 328770

This is called "Polymorphic persistence". There are various ways to do this. All of them have in common that there is a column in the base table which contains the real class of the object in each row.

The OR mapper uses this column to either load more columns of the same table or join columns in other tables.

See the Hibernate docs for more details. Here is an example from Java Tips.

Upvotes: 1

Related Questions