그룹과 사용자라는 두 개의 엔티티가 있다고 가정 해 보겠습니다. 모든 사용자는 여러 그룹의 구성원이 될 수 있으며 모든 그룹은 여러 사용자를 가질 수 있습니다.
@Entity
public class User {
@ManyToMany
Set<Group> groups;
//...
}
@Entity
public class Group {
@ManyToMany(mappedBy="groups")
Set<User> users;
//...
}
이제 그룹을 제거하고 싶습니다 (구성원이 많다고 가정 해 보겠습니다).
문제는 일부 그룹에서 EntityManager.remove ()를 호출 할 때 JPA 공급자 (내 경우에는 Hibernate) 가 조인 테이블에서 행을 제거하지 않고 외래 키 제한으로 인해 삭제 작업이 실패한다는 것입니다. 사용자에 대한 remove () 호출은 잘 작동합니다 (나는 이것이 관계의 소유와 관련이 있다고 생각합니다).
그렇다면이 경우 어떻게 그룹을 제거 할 수 있습니까?
내가 생각 해낼 수있는 유일한 방법은 그룹의 모든 사용자를로드 한 다음 모든 사용자에 대해 그룹에서 현재 그룹을 제거하고 사용자를 업데이트하는 것입니다. 그러나이 그룹을 삭제할 수 있도록 그룹의 모든 사용자에 대해 update ()를 호출하는 것은 우스꽝스러운 것 같습니다.
답변
- 관계의 소유권은 ‘mappedBy’속성을 주석에 배치하는 위치에 따라 결정됩니다. ‘mappedBy’를 넣은 엔티티는 소유자가 아닙니다. 양측이 모두 소유자가 될 기회는 없습니다. ‘사용자 삭제’사용 사례가없는 경우
Group
현재User
소유자이므로 소유권을 엔티티 로 간단히 이동할 수 있습니다. - 반면에, 당신은 그것에 대해 묻지 않았지만 알아야 할 가치가 있습니다.
groups
와는users
서로 결합되지 않습니다. 내 말은, Group1.users에서 User1 인스턴스를 삭제 한 후 User1.groups 컬렉션이 자동으로 변경되지 않습니다. - 대체로 누가 소유자인지 결정하는 것이 좋습니다.
User
주인이 있다고합시다 . 그런 다음 사용자를 삭제할 때 관련 사용자 그룹이 자동으로 업데이트됩니다. 그러나 그룹을 삭제할 때는 다음과 같이 관계를 삭제해야합니다.
entityManager.remove(group)
for (User user : group.users) {
user.groups.remove(group);
}
...
// then merge() and flush()
답변
다음은 나를 위해 작동합니다. 관계 (그룹)의 소유자가 아닌 엔터티에 다음 메서드를 추가합니다.
@PreRemove
private void removeGroupsFromUsers() {
for (User u : users) {
u.getGroups().remove(this);
}
}
이것이 작동하려면 그룹에 업데이트 된 사용자 목록이 있어야합니다 (자동으로 수행되지 않음). 따라서 사용자 엔터티의 그룹 목록에 그룹을 추가 할 때마다 그룹 엔터티의 사용자 목록에도 사용자를 추가해야합니다.
답변
가능한 해결책을 찾았지만 … 좋은 해결책인지 모르겠습니다.
@Entity
public class Role extends Identifiable {
@ManyToMany(cascade ={CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinTable(name="Role_Permission",
joinColumns=@JoinColumn(name="Role_id"),
inverseJoinColumns=@JoinColumn(name="Permission_id")
)
public List<Permission> getPermissions() {
return permissions;
}
public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
}
}
@Entity
public class Permission extends Identifiable {
@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinTable(name="Role_Permission",
joinColumns=@JoinColumn(name="Permission_id"),
inverseJoinColumns=@JoinColumn(name="Role_id")
)
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
나는 이것을 시도했고 작동합니다. 역할을 삭제하면 관계도 삭제되고 (권한 엔터티 제외) 권한을 삭제하면 역할과의 관계도 삭제됩니다 (역할 인스턴스는 제외되지 않음). 그러나 우리는 단방향 관계를 두 번 매핑하고 두 엔티티가 관계의 소유자입니다. 이것이 Hibernate에 문제를 일으킬 수 있습니까? 어떤 유형의 문제입니까?
감사!
위의 코드는 다른 게시물 과 관련된 것입니다.
답변
JPA / Hibernate 솔루션의 대안으로 : (Oracle 구문)과 같이 조인 테이블에있는 foregin 키의 데이터베이스 정의에 CASCADE DELETE 절을 사용할 수 있습니다.
CONSTRAINT fk_to_group
FOREIGN KEY (group_id)
REFERENCES group (id)
ON DELETE CASCADE
이렇게하면 그룹을 삭제할 때 DBMS 자체가 그룹을 가리키는 행을 자동으로 삭제합니다. 그리고 삭제가 Hibernate / JPA, JDBC, DB에서 수동으로 이루어 지든 다른 방법 으로든 작동합니다.
계단식 삭제 기능은 모든 주요 DBMS (Oracle, MySQL, SQL Server, PostgreSQL)에서 지원됩니다.
답변
그 가치가 무엇인지 EclipseLink 2.3.2.v20111125-r10461을 사용하고 있으며 @ManyToMany 단방향 관계가 있으면 설명하는 문제를 관찰합니다. 그러나 양방향 @ManyToMany 관계로 변경하면 비 소유 측에서 엔티티를 삭제할 수 있으며 JOIN 테이블이 적절하게 업데이트됩니다. 이것은 모든 캐스케이드 속성을 사용하지 않고 있습니다.
답변
이것은 나를 위해 작동합니다.
@Transactional
public void remove(Integer groupId) {
Group group = groupRepository.findOne(groupId);
group.getUsers().removeAll(group.getUsers());
// Other business logic
groupRepository.delete(group);
}
또한 @Transactional (org.springframework.transaction.annotation.Transactional) 메소드를 표시하면 한 세션에서 전체 프로세스를 수행하고 시간을 절약 할 수 있습니다.
답변
이것은 좋은 해결책입니다. 가장 좋은 부분은 SQL 측에 있습니다. 모든 레벨로의 미세 조정이 쉽습니다.
MySql 및 MySql Workbench를 사용하여 필수 외래 키를 삭제할 때 계단식으로 배열했습니다.
ALTER TABLE schema.joined_table
ADD CONSTRAINT UniqueKey
FOREIGN KEY (key2)
REFERENCES schema.table1 (id)
ON DELETE CASCADE;
