java - JPA/Hibernate 中的单独表与额外列

标签 java database hibernate jpa orm

我想知道使用 Hibernate 进行数据库设计的最佳实践。

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

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

我正在谈论的一个例子可以用

来说明
@Entity
public class User{

@OneToOne
private ForumSettings forumSettings;

@OneToOne
private AccountSettings accountSettings;

@OneToOne
private SecuritySettings securitySettings;

}

对比

@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:将 UserSettings 存储为实体作为映射为一对多关系

    @Entity
    public class User

    @OneToMany
    private List<UserSettings> userSettings;

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

例如(JPQL)

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

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

 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 集合将存储在一个单独的表中,外键User 表。 UserSettings 没有自己的持久性 ID,依赖于 User 实体,只能通过它的父级('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;

关于java - JPA/Hibernate 中的单独表与额外列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45383087/

相关文章:

java - JMenu 项在单击其他位置之前不会调用方法

java - 如何创建正则表达式模式来验证android中的edittext?

php - 主键 + 复合主键导致推进数据库模式出现问题

mysql - 拥有许多 MySQL 表的缺点?

php - 如何在Mysql中实现Join来获取以下记录

java - 如何使用 hibernate 使用现有对象创建复合键对象

java - 如何在应用程序级别缓存复杂的java对象

java - ScriptEngineManager.getEngineFactories 在 appengine 上不返回任何工厂

java - Android 中切换状态播放、暂停、停止

mysql - 如何在 jpa 和 PagingAndSortingRepository 中设置每页限制结果?