【问题标题】:Override @CollectionTable reference to primary-key column覆盖 @CollectionTable 对主键列的引用
【发布时间】:2016-09-09 14:53:37
【问题描述】:

总之

JPA 文档说CollectionTable.joinColumns 属性是“引用实体主表的集合表的外键列。”

我可以让它引用的不是实体表的主键列,而是另一个具有唯一值的列吗?

详情

有一个带有以下表格的旧数据库(简化):

staff:
  user_id (int)
  user_name (varchar, primary key)

staff_privileges:
  id_user (int)
  privileges_id (int) 
  privileges_status (boolean)

现在我正在将 Hibernate 引入项目并尝试将此表映射到实体:

@Entity
@Table(name = "staff")
public class User {

  @Column(name = "user_id")
  private Integer userId;

  @Id
  @Column(name = "user_name")
  private String userName;    // primary key column (legacy, cannot be changed)

  @ElementCollection
  @CollectionTable(name = "staff_privileges", joinColumns = @JoinColumn(name = "id_user"))
  @MapKeyColumn(name = "privileges_id")
  @Column(name = "privileges_status")
  private Map<Integer, Boolean> privileges; // privilegeId <-> isEnabled
}

不起作用,因为@CollectionTable 创建了对主键的引用:staff_privileges.id_user -&gt; staff.user_name (primary key)。 应该是:staff_privileges.id_user -&gt; staff.id_user。 有没有办法覆盖这个参考?是否有任何 Hibernate 或 JPA 注释?我想保持简单,尽可能不引入任何新的实体或嵌入。

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    您可以使用refrencedColumnName 映射id_user 而不是user_name 作为连接列。

    Hibernate documentation对此参数有更简洁的描述:

    连接列是用@JoinColumn 注释声明的 看起来像 @Column 注释。它还有一个名为的参数 referencedColumnName该参数在 将用于加入的目标实体。请注意,使用时 referencedColumnName 到非主键列,关联类 必须是可序列化的。另请注意,referencedColumnName 为 非主键列必须映射到具有单个 列(其他情况可能不起作用)。

    所以在你的情况下(用Hibernate 5.4.29.Final测试):

    (我实现了Serializable 以避免将bug 关联到referencedColumnName

    @Entity
    @Table(name = "staff")
    public class User implements Serializable {
      private static final long serialVersionUID = 1L;
      ...
    
      @ElementCollection
      @CollectionTable(name = "staff_privileges", joinColumns = @JoinColumn(name = "id_user", referencedColumnName = "user_id"))
      @MapKeyColumn(name = "privileges_id")
      @Column(name = "privileges_status")
      private Map<Integer, Boolean> privileges;
    }
    

    有关更多信息,请查看此 SO 问题:What is referencedColumnName used for in JPA?

    【讨论】:

    • 这个答案是错误的你不能在referenceColumnName中使用源实体列,你在join列中颠倒了name和referencedColumnName的顺序,会抛出异常。
    • @theNoobProgrammer 我不认为我将 @JoinColumn 中的列从 referencedColumnName 文档中颠倒了:...When used in a CollectionTable mapping, the referenced column is in the table of the entity containing the collection。我刚刚更新了修复ClassCastException的答案
    【解决方案2】:

    假设 user_id 对于每个用户也是唯一的,那么您可以简单地将 User 上的 @Id 注释移动到 userId:您的 JPA 提供者不知道数据库中的实际 PK 是什么,因此只要该值是唯一的,就不会引起任何问题。

    上下文略有不同,但请参阅:

    https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#No_Primary_Key

    JPA Id 并不总是必须与数据库表主表匹配 键约束,也不需要主键或唯一约束。

    唯一的区别是,如果您从映射中对表进行逆向工程,那么将使用 user_id 而不是 user_name 上的 PK 创建人员表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-29
      • 2011-01-29
      • 2014-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-18
      • 2020-11-11
      相关资源
      最近更新 更多