Сохранить сущность с помощью FK "reuse" - PullRequest
0 голосов
/ 02 ноября 2019

Я использую Spring + Hibernate JPAA.

У меня есть сущность:

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

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

, и существует таблица М-М, связывающая A.id, B.id.

, если пользователь создает объект:

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

Сохраняет, но создает новую запись в таблице B. Рассматривайте B как таблицу «Роли», определенную системой, она не должна меняться. Поэтому я хочу, чтобы он снова использовал Admin и автоматически заполнил id. Этот объект происходит из API REST… Ожидается ли в этом случае, чтобы вызывающий абонент знал идентификатор и имя? или они просто должны быть в состоянии заполнить по идентификатору или имени?

Как справиться с этой ситуацией? Или было бы лучше избавиться от идентификатора и иметь имя в качестве PK?

РЕДАКТИРОВАТЬ: уточнить ...

Пользователь сущности Роль сущности Таблица UserRole с User.Id, Роль.Id отношение M2M.

Таблица ролей содержит: 1 пользователя 2 администратора 3 суперпользователя

Это определенная мной таблица fixed . Вызывающему не разрешается добавлять роли.

Так что, если Пользователь1 является Пользователем, тогда в таблице M2M будет запись 1,1.

Теперь представьте, если кто-то проходит вновый пользовательский объект User2 с ролью «Пользователь». Как и сейчас, он создает запись в Roles id = 4 value = User (дублирующаяся запись), а в таблице M2M создает 1,4, где предполагаемое поведение равно 1,1, то есть повторно использует существующего «пользователя»role.

По сути, я думаю, что для вызывающего абонента имеет смысл знать идентификатор пользователя, но я не уверен, имеет ли смысл для вызывающего абонента знать идентификатор роли? кажется, больше похоже, что они будут знать возможные роли. Что-то вроде поведения типа enum?

@ Entity @Table (name = "Customers") открытый класс Customer {

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

@ Entity @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 голосов
/ 02 ноября 2019

Трудно понять, что происходит без полного кода. Но в целом вы должны рассмотреть следующую концепцию:

Сущность с аннотацией 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 отношений. Если это не соответствует вашему сценарию, предоставьте свой код с дополнительной информацией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...