java - 使用 FK "reuse"保存实体

标签 java spring hibernate

我正在使用 Spring + Hibernate JPAA。

我有一个实体:

A
  id (PK)
  Set<B> b;
  otherProps…

B
  id (PK)
  String name; (unique)
  otherProps…

并且有一个 M 到 M 表链接 A.id、B.id。

如果用户创建一个实体:

A.id = 0
A.b.id = 0
A.b.Name = "Admin";

它保存了,但在 B 表中创建了一个新条目。将 B 视为系统定义的“角色”表,它不应该更改。所以我希望它重新使用 Admin 并自动填充 id。该对象来自 REST api…在这种情况下调用者是否应该知道 id 和名称?或者他们应该只能通过 id 或名称填充?

遇到这种情况该如何处理?或者去掉 id 并用 name 作为 PK 会更好吗?

编辑:澄清...

用户实体 角色实体 UserRole 表与 User.Id、Role.Id M2M 关系。

角色表包含​​: 1 位用户 2 管理员 3 super 用户

这是我定义的固定表。不允许调用者添加角色。

因此,如果User1是用户,那么M2M表1,1中将会有一个条目。

现在,想象一下如果有人传入一个角色为“User”的新用户对象 User2。就像现在一样,它在 Roles id=4 value=User 中创建一个条目(重复条目),并在 M2M 表中创建一个 1,4,其中预期行为为 1,1,即重用现有的“User”角色。

基本上,我认为调用者知道用户 id 是有意义的,但我不确定调用者知道角色 id 是否有意义?似乎他们更了解可能的角色。有点像枚举类型的行为?

@Entity @Table(名称=“客户”) 公共(public)类客户{

@ApiModelProperty(notes="Id of the customer.", required=true, value="100000")
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long customerId;
@NotNull
@Size(min=2, max=64)
@ApiModelProperty(notes="First name of the customer.", required=true, value="John")
private String firstName;
@NotNull
@Size(min=2, max=64)
@ApiModelProperty(notes="Last name of the customer.", required=true, value="Smith")
private String lastName;
@ManyToMany(cascade={ CascadeType.MERGE })
@JoinTable(name="CustomerRoles",
           joinColumns={ @JoinColumn(name="CustomerId") },
           inverseJoinColumns={ @JoinColumn(name="RoleId") }
)
private Set<Role> roles = new HashSet<>();

public Long getCustomerId() {
    return this.customerId;
}

public String getFirstName() {
    return this.firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return this.lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public List<Role> getRoles() {
    return new ArrayList<Role>(this.roles);
}

@实体 @Table(名称=“角色”) 公共(public)类角色{

@ApiModelProperty(notes="Id of the role.", required=true, value="1")
@Id
//@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long roleId;
@NotNull
@Size(min=2, max=64)
@ApiModelProperty(notes="Name of the role.", required=true, value="Admin")
private String name;

@ManyToMany(mappedBy = "roles")
private Set<Customer> roles = new HashSet<Customer>();

public Long getRoleId() {
    return this.roleId;
}

public String getName() {
    return this.name;
}

public void setName(String name) {
    this.name = name;
}

}

最佳答案

如果没有完整的代码,很难弄清楚发生了什么。 但总的来说,您应该考虑以下概念:

带有JoinTable注释的实体是关系的Owner。这意味着如果您在“Owner”上启用Cascade.Merge,向其中添加新记录,则会向中间表添加另一条记录。

示例

角色实体:

{
  @ManyToMany(cascade = {CascadeType.MERGE})
    @JoinTable(name = "tb_role_privilege",
            joinColumns = @JoinColumn(name = "role_id"),
            inverseJoinColumns = @JoinColumn(name = "privilege_id"))
    private Set<Privilege> privileges = new HashSet<>();
}

权限实体:

{
      @ManyToMany(mappedBy = "privileges")
    private Set<Role> roles = new HashSet<Role>();
}

这里,Role 是关系的所有者。当您使用 id=0 创建角色对象并使用 ids=[0 1 2] 填充其权限列表,然后调用 save 时,它将向 tb_role 插入角色记录,并且还将 (0,0)、(0,1) 和 (0,2) 插入到中间表 tb_role_privilege 中, 但它不会在tb_privilege中插入任何内容。因此,在插入角色记录之前,需要先将权限记录插入到tb_privilege中。

对于 m2m 关系来说,这是一种很好且简单的方法。如果它不满足您的场景,请为您的代码提供更多信息。

关于java - 使用 FK "reuse"保存实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58666854/

相关文章:

java - 使用java对mongodb中的子文档数组进行排序

java - map 中的 Spring 枚举

spring - Spring Mvc项目中如何设置Context root

java - Spring Data JPA无法找到带有id的对象

java - 在java中无需硬编码即可设置文件位置

java - 每个对话 session 的好处是什么?

java - Spring Boot 使用 JSON Sanitizer?

java - 将 Spring Boot 与现有 Spring 应用程序集成

java - 如何在 hibernate 中向 OneToMany 映射添加限制

java - 在bluej中编译?