首页 > 解决方案 > JPA,如何将 Map 中实体类型的值添加到主键?

问题描述

我有 3 个实体类,如下所示:-

角色实体

@Entity
public class Role {

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

    @ManyToMany
    @LazyCollection(LazyCollectionOption.FALSE)
    @JoinTable(name = "roles_privileges", joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "privilege_id", referencedColumnName = "id"))
    private Set<Privilege> privileges;

    // getters, setters etc

}

特权实体

@Entity
public class Privilege {

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

    private String name;

    @ManyToMany(mappedBy = "privileges", fetch = FetchType.EAGER)
    @JsonIgnore
    private Set<Role> roles;

    // getters, setters etc

}

UrlsMapper 实体

@Entity(name = "urls_mapper")
@Table(name = "urls_mapper")
public class UrlsMapper {

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

    @Enumerated(EnumType.STRING)
    @Column(name = "http_method")
    private HttpMethod httpMethod;

    @Column(name = "path")
    private String path;

    @ManyToMany(fetch = FetchType.EAGER)
    @MapKeyJoinColumn(name = "role_id", referencedColumnName = "id")
    @JoinTable(
        name = "u_r_p",
        inverseJoinColumns = @JoinColumn(name = "privilege_id")
    )
    Map<Role, Privilege> privilegeMap;

   // getters, setters etc

}

创建的键、主键和外键如下

在此处输入图像描述

表生成时的日志如下:-

Hibernate: create table u_r_p (urls_mapper_id bigint not null, privilege_id bigint not null, role_id bigint not null, primary key (urls_mapper_id, role_id)) engine=InnoDB
Hibernate: alter table u_r_p add constraint FKgd7gd9f9ded1s28swdudqs0ro foreign key (privilege_id) references Privilege (id)
Hibernate: alter table u_r_p add constraint FKrryprkx4j60lyjti16eysn5g5 foreign key (role_id) references Role (id)
Hibernate: alter table u_r_p add constraint FKfkthdnoca59a18ba96183p7ov foreign key (urls_mapper_id) references urls_mapper (id)

而且我只想知道如何将 privilege_id 也添加到 JoinTable u_r_p 中,以及是否有其他最佳选择。在数据库中手动执行是一个明显的替代方案,但我想知道基于 hbm2ddl.auto 的解决方案,以便代码自行管理

标签: javamysqlspringhibernatejpa

解决方案


我认为您没有正确建模您的概念。你有一个ManyToMany介于两者之间的东西RolePriviledge但是是什么构成UrlMapper了一个实体?您有一个Map<Role, Privilege>字段,UrlMapper但这是连接表的目的,因此不需要复制它。相反,它似乎是这种HttpMethod关系Path的属性。

在此处输入图像描述

但是,我可能还注意到,您似乎期望有许多不同的 HttpMethod/Path 组合的角色/权限连接。这似乎令人难以置信的细粒度和操作噩梦,但无论如何。无论如何,您似乎在说的是您想要角色/特权/HttpMethod/Path 的独特组合,因此您应该为此创建一个实体,并且该表代表您的集合。创建一个拥有唯一角色/权限/HttpMethod/Path 的权限实体。Role、Privilege、HttpMethod 甚至 Path 本质上都是枚举,因此您应该为每个枚举都有一个表,并ManyToOne在 Permission 实体中进行映射。您可以在每个查找表中添加双向OneToMany映射,但我不确定是否需要这样做。由你决定。

在此处输入图像描述

我假设Privilege会是 {allow, deny} 但如果您假设拒绝,除非明确存在 Role/HttpMethod/Path 权限,否则它似乎不那么纠结。如果是这种情况,那么我会忽略该Privilege实体。无论如何,只是一个想法。希望这可以帮助。


推荐阅读