Spring Data удаляет сопоставленные объекты - PullRequest
0 голосов
/ 12 июля 2020

У меня есть классы Account и Role, сопоставленные «многие ко многим», тестовый класс и класс контроллера. Когда я запускаю тест, все в порядке, но в контроллере тот же код не работает (точнее, первый вызов контроллера удаляет только сопоставление в таблице учетных записей в postgres, и только второй вызов контроллера удаляет все учетные записи). Так почему же один и тот же код по-разному действует в тесте и в контроллере? Есть ли какой-либо скрытый контроль транзакций? Здесь или в Google нет вопросов с такой же проблемой: (* ​​1001 *

Ниже объектов, тест и контроллер.

Класс учетной записи

 package github.aaa4.server.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

@Entity
@Data
@NoArgsConstructor
public class Account extends PersistenceUnit {

    private String name;
    private String email;
    private String encodedPassword;

    public Account(String name) {
        this.name = name;
    }

    public Account(String name, String email) {
        this.name = name;
        this.email = email;
    }

    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @JoinTable(name = "account_role",
            joinColumns = {@JoinColumn(name = "account_id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id")})
    Set<Role> roles = new HashSet<>();


    @EqualsAndHashCode.Exclude
    @ToString.Exclude
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "account")
    Set<VerificationToken> tokens = new HashSet<>();


    public void addNewRole(Role role) {
        if (roles == null) {
            roles = new HashSet<>();
        }
        roles.add(role);
        role.getAccounts().add(this);
    }

    public void removeRole(Role role) {
        roles.remove(role);
        role.getAccounts().remove(this);
    }


    public void addNewToken(VerificationToken token) {
        if (tokens == null)
            tokens = new HashSet<>();
        tokens.add(token);
        token.setAccount(this);
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Account)) return false;
        if (!super.equals(o)) return false;
        Account account = (Account) o;
        return Objects.equals(name, account.name) &&
                Objects.equals(email, account.email);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), name, email);
    }
}

Роль. Класс

package github.aaa4.server.entity;

import lombok.*;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

@Entity
@Data
@NoArgsConstructor
@RequiredArgsConstructor
public class Role extends PersistenceUnit {

    @NonNull
    private Roles role;


    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    @ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER,
            cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    private Set<Account> accounts = new HashSet<>();


    public void addNewAccount(Account account){
        if (accounts == null){
            accounts = new HashSet<>();
        }
        accounts.add(account);
        account.getRoles().add(this);
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Role)) return false;
        if (!super.equals(o)) return false;
        Role role1 = (Role) o;
        return role == role1.role;
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), role);
    }


    @Override
    public String toString() {
        return "Role{" +
                "role=" + role +
                ", accounts=" + accounts +
                '}';
    }
}

SQL для таблицы

create table if not exists account (
  id               uuid not null primary key,
  name             varchar(30),
  email            varchar(50),
  encoded_password varchar(50),
  created_at       timestamp,
  updated_at       timestamp
);

create table if not exists role (
  id         uuid not null primary key,
  role       integer,
  created_at timestamp,
  updated_at timestamp
);


create table if not exists account_role (
  account_id uuid,
  role_id    uuid,
  constraint fk_account_id
  foreign key (account_id)
  references account (id),
  constraint fk_role_id
  foreign key (role_id)
  references role (id)
);

Класс испытаний

package github.aaa4.server.newTests;

import github.aaa4.server.entity.Account;
import github.aaa4.server.entity.Role;
import github.aaa4.server.entity.Roles;
import github.aaa4.server.repo.AccountRepository;
import github.aaa4.server.repo.RoleRepository;
import github.aaa4.server.services.AccountAndRoleService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.assertEquals;

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestDeletion {

    @Autowired
    RoleRepository roleRepository;
    @Autowired
    AccountAndRoleService service;
    @Autowired
    AccountRepository accountRepository;

    Account editorsAccount = new Account("Ikki");
    Role editor = new Role(Roles.EDITOR);

 
    @Test
    public void deleteAllTest(){
        roleRepository.save(editor);
        service.saveAccount(editorsAccount);
        editorsAccount.addNewRole(editor);
        service.saveAccount(editorsAccount);

        assertEquals(editorsAccount, accountRepository.findDistinctByName(editorsAccount.getName()).get());

        service.findAll().forEach(account -> service.deleteAccount(account));
        assertEquals(0,accountRepository.findAll().size());
    }
    
}

Класс контроллера

package github.aaa4.server.web.controllers.web;

import github.aaa4.server.entity.Account;
import github.aaa4.server.entity.Role;
import github.aaa4.server.entity.Roles;
import github.aaa4.server.repo.AccountRepository;
import github.aaa4.server.services.AccountAndRoleService;
import github.aaa4.server.web.controllers.web.DTO.AccountDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/users")
class RegistrationController {


    @Autowired
    AccountAndRoleService service;

    @Autowired
    AccountRepository accountRepository;

    @GetMapping("/devclear")
    public String deleteAll() {
        service.findAll().forEach(account -> service.deleteAccount(account));
        return "done!";
    }
}

Класс обслуживания

package github.aaa4.server.services;

import github.aaa4.server.entity.Account;
import github.aaa4.server.entity.Role;
import github.aaa4.server.entity.Roles;
import github.aaa4.server.entity.VerificationToken;
import github.aaa4.server.repo.AccountRepository;
import github.aaa4.server.repo.RoleRepository;
import github.aaa4.server.repo.VerificationTokenRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
@Slf4j
public class AccountAndRoleService {
  public void deleteAccount(Account account){
        account.setRoles(new HashSet<>());
        accountRepository.save(account);
        accountRepository.delete(account);
    }
}

Спасибо, что прочитали этот вопрос :).

...