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 -> staff.user_name (primary key)
。
它应该是:staff_privileges.id_user -> staff.id_user
。
有没有办法覆盖这个参考?是否有任何Hibernate或JPA注释?我想保持简单,如果可能的话,不要引入任何新的实体或嵌入。
答案 0 :(得分:3)
假设每个用户user_id
也是唯一的,那么您只需将@Id
注释User
移至userId
:您的JPA提供商不知道实际的PK在数据库中,只要该值是唯一的,就不会引起任何问题。
略有不同的背景但请参阅:
https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#No_Primary_Key
JPA Id并不总是必须匹配数据库表primary 键约束,也不是主键或唯一约束。
唯一的区别是,如果您从映射中对表进行逆向工程,那么将在user_id而不是user_name上使用PK创建staff表。
答案 1 :(得分:0)
您可以使用refrencedColumnName
将id_user
而不是user_name
映射为加入列。
Hibernate documentation对此参数有更简洁的描述:
使用@JoinColumn注释声明连接列 看起来像@Column注释。它还有一个名为的参数 的 referencedColumnName 即可。 此参数声明了列中的列 将用于加入的目标实体。请注意,使用时 referencedColumnName 到非主键列,关联类 必须是可序列化的。另请注意,referencedColumnName为a 非主键列必须映射到具有单个的属性 列(其他情况可能不起作用)。
@Entity
@Table(name = "staff")
public class User {
...
@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;
}
有关详情,请查看此问题:What is referencedColumnName used for in JPA?