简体   繁体   中英

Separate Table vs Extra Columns in JPA/Hibernate

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM