JPA / Hibernate中的独立表与额外列

时间:2017-07-28 22:11:10

标签: java database hibernate jpa orm

我想知道Hibernate在数据库设计方面的最佳实践。

我有一个用户实体将具有很多的不同设置。对于每组设置,我必须在User表中将它们添加为额外列,或者创建一个单独的实体并将它们与@OneToOne关系连接起来。我的理解是@OneToMany和@ManyToOne关系通常应该在单独的表中进行,因为你不应该有可选的列。

但@OneToOne关系还不清楚。我认为有一种使用@OneToOne的情况,因为默认情况下ORM会选择所有单个属性,并且有很多列会减慢该过程。

我所谈论的一个例子可以用

来说明
@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

}

上面是一个显示概念的简单示例,但实际上第二部分会有更多列。

我知道这可能是基于意见的,但我希望有人可以分享这两种选择的利弊。

非常感谢

1 个答案:

答案 0 :(得分:2)

您的问题一般是关于数据规范化。规范化本身就是一个广泛的研究领域,基本上是一种构建数据库表以避免冗余并确保更新不会引入异常的方法。

规范化的第一条规则是表格不包含重复的组。在你的情况下确实如此。

解决方案1:将UserSettings作为实体存储为地图作为OneToMany关系

    @Entity
    public class User

    @OneToMany
    private List<UserSettings> userSettings;

然后,您可以通过加入settingUser实体来查询特定的UserSettings类型。

例如(JPQL)

  SELECT user u 
  JOIN u.settings us
  WHERE us.settings_type = 'account_settings' 
        and us.settings_value = 'secure' // or any other logic

这种方法的优点是UserSettings将拥有它自己的持久性标识,并且可以由它自己查询。它不依赖于父母。 例如:

 SELECT q from Query q where ...

解决方案2:将设置存储在基本元素集合中

您可以将用户设置存储在集合中(每个用户都有自己的一组设置)

   @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集合将存储在包含foreign keyUser表的单独表格中。 UserSettings没有自己的持久性ID,依赖于User实体,只能通过它来查询父级('用户')

解决方案3:将用户设置存储为嵌入式

嵌入式类型不是实体,它没有自己的持久性ID,并且取决于父类型,存储为数据库中父记录的一部分(在User表中)

@Entity
public class User {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;

    private String name;

    ...

    @Embedded
    private UserSettings userSettings;

UserSettings位于单独的类中,但存储在User表中。

@Embeddable
public class UserSettings {

    private List<String> securitySettings;  // or any other collection type

    private List<Boolean> forumSettings;