Spring-Data-Jpa ManyToMany (пользователь, роль) Как каскадно обновлять промежуточные таблицы (назначать или удалять роли пользователей) - PullRequest
1 голос
/ 09 января 2020

Проблема была решена

Причина в том, что я работаю в тестовой среде и транзакции автоматически откатываются по умолчанию

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {UaaApplication.class})
@Transactional
@Rollback(false) // Turn off automatic rollback

Вот оригинальный вопрос


Моя среда

  • Spring Boot
  • Spring-Data-Jpa
  • Mysql

При сохранении , он добавил данные в таблицу user_roles, что дало ожидаемый эффект.

Hibernate: insert into user_roles (user_id, role_name) values (?, ?)

Однако, когда я попытался добавить новую роль для пользователя, он не добавил данные в таблица user_roles.

Или JPA не может этого сделать? Итак, как я могу достичь своих ожиданий? Спасибо за любые предложения

Пользователь. java

@Entity
@Table(name = "user")
public class User extends AbstractAuditingEntity {

    private static final long serialVersionUID = -7682612894107800662L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 50, unique = true, nullable = false)
    private String login;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(
            name = "user_roles",
            joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "role_name", referencedColumnName = "name")})
    private Set<Role> roles = new HashSet<>();

    public User addRole(Role role) {
        this.roles.add(role);
        return this;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        return login != null ? login.equals(user.login) : user.login == null;
    }

    @Override
    public int hashCode() {
        return login != null ? login.hashCode() : 0;
    }
}

Роль. java

@Entity
@Table(name = "role")
public class Role extends AbstractAuditingEntity {

    private static final long serialVersionUID = -1702863587500414292L;

    @Id
    @Column(name = "name", unique = true, nullable = false)
    private String name;

    @Column(name = "description")
    private String description;

    @ManyToMany
    @JoinTable(
            name = "user_role",
            joinColumns = {@JoinColumn(name = "role_name", referencedColumnName = "name")},
            inverseJoinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")})
    private Set<User> users = new HashSet<>();

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Role role = (Role) o;

        return name != null ? name.equals(role.name) : role.name == null;
    }

    @Override
    public int hashCode() {
        return name != null ? name.hashCode() : 0;
    }
}

Посмотрите на последнюю строку журнала, он вставляет данные в среднюю таблицу

Hibernate: insert into user_roles (user_id, role_name) values (?, ?)

Set<Role> authorities = new HashSet<>();
authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add);
newUser.setRoles(authorities);
userRepository.save(newUser);

log

Hibernate: select user0_.id as id1_7_, user0_.created_by as created_2_7_, user0_.created_date as created_3_7_, user0_.feature as feature4_7_, user0_.last_modified_by as last_mod5_7_, user0_.last_modified_date as last_mod6_7_, user0_.activated as activate7_7_, user0_.activation_key as activati8_7_, user0_.email as email9_7_, user0_.image_url as image_u10_7_, user0_.lang_key as lang_ke11_7_, user0_.login as login12_7_, user0_.nick_name as nick_na13_7_, user0_.password_hash as passwor14_7_, user0_.reset_date as reset_d15_7_, user0_.reset_key as reset_k16_7_ from user user0_ where user0_.login=?
Hibernate: insert into user (created_by, created_date, feature, last_modified_by, last_modified_date, activated, activation_key, email, image_url, lang_key, login, nick_name, password_hash, reset_date, reset_key) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select users0_.role_name as role_nam1_8_1_, users0_.user_id as user_id2_8_1_, user1_.id as id1_7_0_, user1_.created_by as created_2_7_0_, user1_.created_date as created_3_7_0_, user1_.feature as feature4_7_0_, user1_.last_modified_by as last_mod5_7_0_, user1_.last_modified_date as last_mod6_7_0_, user1_.activated as activate7_7_0_, user1_.activation_key as activati8_7_0_, user1_.email as email9_7_0_, user1_.image_url as image_u10_7_0_, user1_.lang_key as lang_ke11_7_0_, user1_.login as login12_7_0_, user1_.nick_name as nick_na13_7_0_, user1_.password_hash as passwor14_7_0_, user1_.reset_date as reset_d15_7_0_, user1_.reset_key as reset_k16_7_0_ from user_role users0_ inner join user user1_ on users0_.user_id=user1_.id where users0_.role_name=?
2020-01-09 10:13:07.007 DEBUG 5452 --- [           main] m.t.s.c.u.service.impl.UserServiceImpl   : Created Information for User: User(id=34, login=user1, password=$2a$10$JTRiBg6Rjblad6hNCUOvBOPbC7zWGHC7/n0uy/Cf7esMWAumvKb56, nickName=user1, email=null, activated=false, langKey=zh, imageUrl=null, activationKey=71667657839259250002, resetKey=null, resetDate=null, roles=[Role(name=ROLE_USER, description=null, users=[], permissions=[])], organizations=[])
Hibernate: insert into user_roles (user_id, role_name) values (?, ?)

Но когда я попытался добавить новую роль пользователю, он не достиг ожидаемого эффекта.

userRepository.findAll().stream().findAny().ifPresent(user -> {
    roleRepository.findByName(AuthoritiesConstants.ADMIN).ifPresent(user::addRole);
    userRepository.save(user);
});

log

Hibernate: select user0_.id as id1_7_, user0_.created_by as created_2_7_, user0_.created_date as created_3_7_, user0_.feature as feature4_7_, user0_.last_modified_by as last_mod5_7_, user0_.last_modified_date as last_mod6_7_, user0_.activated as activate7_7_, user0_.activation_key as activati8_7_, user0_.email as email9_7_, user0_.image_url as image_u10_7_, user0_.lang_key as lang_ke11_7_, user0_.login as login12_7_, user0_.nick_name as nick_na13_7_, user0_.password_hash as passwor14_7_, user0_.reset_date as reset_d15_7_, user0_.reset_key as reset_k16_7_ from user user0_
Hibernate: select role0_.name as name1_5_, role0_.created_by as created_2_5_, role0_.created_date as created_3_5_, role0_.feature as feature4_5_, role0_.last_modified_by as last_mod5_5_, role0_.last_modified_date as last_mod6_5_, role0_.description as descript7_5_ from role role0_ where role0_.name=?
2020-01-09 10:18:07.376  INFO 15044 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@692f203f testClass = UserTests, testInstance = me.talei.spring.cloud.uaa.domain.UserTests@3431cb1f, testMethod = associate@UserTests, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@48f2bd5b testClass = UserTests, locations = '{}', classes = '{class me.talei.spring.cloud.uaa.UaaApplication, class me.talei.spring.cloud.uaa.UaaApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@319b92f3, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@5c18298f, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@71623278, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@17baae6e], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]

1 Ответ

0 голосов
/ 09 января 2020

Причина в том, что я работаю в тестовой среде, и транзакции автоматически откатываются по умолчанию

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {UaaApplication.class})
@Transactional
@Rollback(false) // Turn off automatic rollback
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...