2017-07-28 30 views
1

我想知道与Hibernate的数据库设计的最佳做法。JPA /休眠的独立表vs额外列

我有一个用户实体将有很多不同的设置。对于每组设置,我必须将它们作为额外的列添加到用户表中,或创建一个单独的实体并将它们与@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 

} 

以上可以说明的一个例子是一个简单的例子来说明这个概念,但在实践中会有更多的第二部分的列。

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

非常感谢你

+0

还有['@ Embedded'](https://en.wikibooks.org/wiki/Java_Persistence/Embeddables)属性。 –

+1

为什么不制作基础'设置'类,然后将属性'类型'添加到'设置'类?然后'User'和'Settings'之间的关联可以是'OneToMany'。一般来说,这是更多的数据库设计问题,而不是实现(jpa,hibernate)。你在问什么是如何规范化数据。 – fg78nc

回答

1

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

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

解决方案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都会有它自己的持久性身份,可以通过它自己的查询。它不依赖于父母。 例如:

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; 
+0

我不明白这是如何工作的。每个“UserSettings”具有的列数是固定的数字。但它是可能的帐户设置有4个属性,安全设置有3个属性,论坛设置有7个属性...等 – Solace

+0

哦,其实我想我误解了你的答案。我认为你的意思是“用户设置”(不是复数),每个用户设置都是设置类型和其值的键/值对。但是,这将强制所有的值是相同的类型,如字符串 – Solace

+0

UserSettings应只有一列 - “属性”,每个属性将单独行(如果你有3至7个属性) – fg78nc