I am wondering about best practices in database design with Hibernate.
I have a User entity that is going to have a lot of different settings. For each set of settings, I have to either add them as extra columns in the User table or create a separate entity and connect them with a @OneToOne relationship. It is my understanding that @OneToMany and @ManyToOne relationships should generally take place in separate tables because you should not have columns that are optional.
But it is kind of unclear for @OneToOne relationships. I think there is a case for using @OneToOne because ORMs will select all single attributes by default and having a lot of columns will slow down that process.
An example of what I am talking about can be illustrated by
@Entity
public class User{
@OneToOne
private ForumSettings forumSettings;
@OneToOne
private AccountSettings accountSettings;
@OneToOne
private SecuritySettings securitySettings;
}
vs
@Entity
public class User{
@Column
private boolean showNSFWContent; //Forum Setting
@Column
private int numberOfCommentsPerPage; //Forum Setting
@Column
private boolean subscribedToNewsLetter; //Account Setting
@Column
private boolean isAccountBanned; //Account Setting
@Column
private boolean isTwoFactorAuthenticationEnabled; //Security Setting
@Column
private boolean alertForSuspiciousLogin; //Security Setting
}
The above is a simple example to show the concept, but in practice there would be many more columns in the 2nd portion.
I know that this might be opinion based, but I am hoping someone could share the pros/cons of both choices.
Thank you very much
Your question is in general about Data normalization. Normalization is itself extensive field of study and basically is a way of structuring database tables avoiding redundancy and making sure that updates don't introduce anomalies.
And first rule of normalization says a table shall contain no repeating groups. In your case it does.
SOLUTION 1 : Store UserSettings as Entity as map as OneToMany relationship
@Entity
public class User
@OneToMany
private List<UserSettings> userSettings;
And then you can query for particular setting
type by joining User
and UserSettings
entities.
For example (JPQL)
SELECT user u
JOIN u.settings us
WHERE us.settings_type = 'account_settings'
and us.settings_value = 'secure' // or any other logic
Advantage of this approach is that UserSettings
will have it is own persistence identity and can be queried by it's own. It it is not dependent on parent. For example :
SELECT q from Query q where ...
Solution 2 : Store settings in a collection of basic elements
You can store User Settings in the collection (Each user will have it's own set of settings)
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String name;
...
@ElementCollection
@CollectionTable(name="USER_SETTINGS")
@MapKeyColumn(name="SETTINGS_TYPE")
@Column(name="SETTINGS_VALUE")
Map<String, Boolean> userSettings = new HashMap<>();
UserSettings
collection will be stored in a separate table with foreign key
to User
table. UserSettings
does not have it is own persistence ID, is dependent on User
entity and can be queried only through it is parent ('User')
Solution 3: Store User Settings as Embedded type
Embedded type is not an entity, it does not have it is own persistence ID and is depends on parent type, stored as part of parent record in database (in User
table)
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String name;
...
@Embedded
private UserSettings userSettings;
UserSettings is in separate class, but stored in User
table.
@Embeddable
public class UserSettings {
private List<String> securitySettings; // or any other collection type
private List<Boolean> forumSettings;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.