使用FK“重用”保存实体

时间:2019-11-01 23:10:28

标签: 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并将其命名为PK会更好?

编辑:以澄清...

用户实体 角色实体 具有User.Id,Role.Id M2M关系的UserRole表。

角色表包含​​: 1位使用者 2个管理员 3个超级用户

那是我定义的固定表。不允许呼叫者添加角色。

因此,如果User1是用户,则M2M表1,1中将存在一个条目。

现在,假设某人是否传入了角色为“用户”的新用户对象User2。现在,它在Roles id = 4 value = User(重复项)中创建一个条目,并在M2M表中创建一个1,4,其中预期行为为1,1,即重用现有的“ User”角色。

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

@实体 @Table(name =“客户”) 公共类客户{

@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(name =“角色”) 公共类角色{

@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;
}

}

1 个答案:

答案 0 :(得分:0)

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

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

示例

Role实体:

{
  @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<>();
}

Privilege实体:

{
      @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关系的好方法。如果不符合您的情况,请为您的代码提供更多信息。