I'm developing an app with a user management system. There is a database table named user
with the following columns:
| Column Name | Column Type |
|-----------------|-------------|
| userId | BIGINT |
| email | TEXT |
| firstName | TEXT |
| lastName | TEXT |
| passwordDigest | TEXT |
| birthday | DATE |
| address | TEXT |
The most straightforward design is to create a Hibernate entity called User
:
@Entity
@Table(name = "user")
public class User {
@Id
private long userId;
private String email;
private String firstName;
private String lastName;
private String passwordDigest;
private LocalDate birthday;
private String address;
}
However, the general user info (i.e. email, first name, last name, birthday, address) and password are getting updated in separate pages in my app. Specifically, there is a "Edit Your General Info" page for users to update their general info, and there is a separate "Update Your Password" page for users to update their passwords. Just like lots of other apps.
Therefore, if I'm using the User
entity above, the code for each pages will be:
void updateUserGeneralInfo (User newUser) {
User oldUser = userDao.getExistingUser(newUser.getUserId());
newUser.setPasswordDigest(oldUser.getPasswordDigest());
userDao.updateUser(newUser);
}
void updateUserPassword (long userId, String newPassword) {
User oldUser = userDao.getExistingUser(userId);
oldUser.setPasswordDigest(calculateDigest(newPassword)); // auto save to DB by Hibernate
}
The problem lies in updateUserGeneralInfo()
. Since newUser
is passed from GUI, it doesn't contain a passwordDigest
. Therefore, directly calling updateUser(newUser)
would wipe out the user's passwordDigest
in the DB. To avoid that, it's necessary to retrieve the user's existing entity just to fill in the password digest, so that updateUser(newUser)
won't affect the user's passwordDigest
. This is kind of clunky and hard to maintain.
To solve the problem, I'm thinking about creating 2 Hibernate entities that maps to the same database table user
:
@Entity
@Table(name = "user")
public class UserGeneralInfo {
@Id
private long userId;
private String email;
private String firstName;
private String lastName;
private LocalDate birthday;
private String address;
}
@Entity
@Table(name = "user")
public class UserCredential {
@Id
private long userId;
private String passwordDigest;
}
The code for the above-mentioned pages will then be:
void updateUserGeneralInfo (UserGeneralInfo newUserGeneralInfo) {
userDao.updateUserGeneralInfo(newUserGeneralInfo);
}
void updateUserPassword (long userId, String newPassword) {
UserCredential newUserCredential = new UserCredential(userId, calculateDigest(newPassword));
userDao.updateUserCredential(newUserCredential);
}
With this new design, the code is much clearer because the responsibility for each method is isolated. updateUserGeneralInfo()
won't worry about wiping out user's passwordDigest
anymore, and updateUserPassword()
won't touch any part of the user
table other than userId
and passwordDigest
.
My question is: is the new design (i.e. separating UserGeneralInfo
and UserCredential
rather than a single User
) a really good design? Is there any disadvantage that I'm not aware of? Furthermore, is it a common design pattern for generic user management systems? Thanks!