복붙노트

[SPRING] 스프링 데이터 JPA 분리 엔터티

SPRING

스프링 데이터 JPA 분리 엔터티

스프링 데이터 JPA를 사용하여 스프링 부트 애플리케이션으로 작업하여 사용자와 롤 간의 ManyToMany 관계를 설정하기 시작했습니다.

이 관계는 User 클래스에서 다음과 같이 정의됩니다.

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name="user_role", joinColumns = {@JoinColumn(name="user_id")}, inverseJoinColumns = {@JoinColumn(name="role_id")})
private Set<UserRole> roles;

다음을 사용하여 역할을 만듭니다.

@Transactional
private void generateSeedRoles() {
    UserRole adminRole = new UserRole(RoleEnum.ADMIN.toString());
    userRoleRepository.save(adminRole);

    UserRole userRole = new UserRole(RoleEnum.USER.toString());
    userRoleRepository.save(userRole);
}

나중에 사용자에게 역할 할당 실패 :

@Transactional
private void generateSeedUsers() {
    UserRole adminRole = userRoleRepository.findUserRoleByRoleName("ADMIN");

    User user = User.createUser("user1", "user1@user.com", "pass");
    user.setRoles(new HashSet<UserRole>(Arrays.asList(adminRole)));

    userRepository.save(user);
}

다음과 같은 예외가 발생합니다 (가독성을 위해 형식이 지정됨).

org.springframework.dao.InvalidDataAccessApiUsageException: 
detached entity passed to persist: co.feeb.models.UserRole; 
nested exception is org.hibernate.PersistentObjectException: 
detached entity passed to persist: co.feeb.models.UserRole

그러나 관계가 만들어지기 전에 사용자가 저장되면 제대로 작동합니다.

@Transactional
private void generateSeedUsers() {
    UserRole adminRole = userRoleRepository.findUserRoleByRoleName("ADMIN");

    User user = User.createUser("user1", "user1@user.com", "pass");
    //Save user
    userRepository.save(user);

    //Build relationship and update user
    user.setRoles(new HashSet<UserRole>(Arrays.asList(adminRole)));
    userRepository.save(user);
}

사용자를 두 번 저장 / 업데이트하는 것은 나에게 다소 불합리한 것처럼 보입니다. 사용자를 먼저 저장하지 않고 새 사용자에게받은 역할을 할당 할 수있는 방법이 있습니까?

해결법

  1. ==============================

    1.엔티티를 저장할 때, Spring은 엔티티가 새로운 것인지를 내부적으로 검사하고 (정확한 메커니즘을 잊어 버림) 영속 (새 경우) 또는 병합 (존재하는 경우) 중 하나를 발행합니다.

    엔티티를 저장할 때, Spring은 엔티티가 새로운 것인지를 내부적으로 검사하고 (정확한 메커니즘을 잊어 버림) 영속 (새 경우) 또는 병합 (존재하는 경우) 중 하나를 발행합니다.

    사용자가 Cascade.ALL과 UserRole 관계를 정의 했으므로 User의 지속성 / 병합이 UserRole에도 캐스케이드됩니다.

    Spring이 저장을 구현하는 방법과 위에 계단식으로 동작하는 방법을 고려할 때 다음과 같은 몇 가지 시나리오를 고려해야합니다.

    사용자와의 관계에 추가 한 UserRole이 항상 존재 함을 보장 할 수 있으면 계단식 옵션에서 Cascade.Persist를 제거하면됩니다. 그렇지 않으면 위의 두 시나리오에서 사용자를 저장할 때 사용자 지정 저장소 및 entityManager를 통해 병합을 사용해야한다고 생각합니다.

    이 상황에서 아마도 이해가되지 않는 Cascade.ALL의 사용에 관해서는 @ManyToMany 관계가 있기 때문에 User에서 UserRole까지 모두를 계단식으로 연결하면 원하지 않는 결과가 발생할 수 있습니다 (예 : Cascade.Remove는 매번 UserRole을 제거합니다 사용자가 삭제됨).

  2. from https://stackoverflow.com/questions/31037503/spring-data-jpa-detached-entity by cc-by-sa and MIT license