JpaRepository @ManyToMany - Jak dodać dane tylko do dwóch tabel?

0

Cześć,
mam 3 tabele:

user image

i dwie klasy domenowe User i Role:

@Entity
@Table(name = "users")
public class User implements Serializable {
    
    private static final long serialVersionUID = 893284018826505486L;
    
    @Id
    @Column(name = "iduser")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int idUser;
    
    @Column(name = "email")
    private String email;
    
    @Column(name = "username")
    private String username;
    
    @Column(name = "password")
    private String password;
    
    @Column(name = "active")
    private boolean active;
    
    @Column(name = "idprofilepicture")
    private int idProfilePicture;
    
    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "rolesofusers",
               joinColumns = @JoinColumn(name = "iduser", referencedColumnName = "iduser"),
               inverseJoinColumns = @JoinColumn(name = "idrole", referencedColumnName = "idrole"))
    private List<Role> roles;

	...
@Entity
@Table(name = "roles")
public class Role {
    
    @Id
    @Column(name = "idrole", unique = true)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int idRole;
    
    @Column(name = "name")
    private String name;
    
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "roles", cascade = CascadeType.ALL)
    private List<User> users;

	...

Repozytoria są tworzone przez JpaRepository.
Przed dodaniem nowego użytkownika w UserService dodaję rolę do listy:

   @Override
    public void save(User user) {
        List<Role> roles = new ArrayList<>();
        Role role = new Role("USER");
        roles.add(role);
        user.setRoles(roles);
	...
        userRepository.save(user);
    }

Ale jest problem, bo role się duplikują

538ed8c4e6.png

Można coś zrobić żeby JpaRepository dodawało dane tylko do dwóch tabel? Czy trzeba tworzyć własną implementację?

1

Może tak unique na name w roles?

Jak robisz new Role() i CascadeType.ALL to co się dziwisz, że tworzą się nowe wpisy?

1

Sugeruję też używanie typu danych Set zamiast List.
A kolumny Id niech będą po prostu id a nie idrole.

0

Ustawiłem 'unique' na name, zamieniłem List na Set oraz wywaliłem kaskadowanie. Działa :)
Ale chyba głównie przez tę kaskadę nie działało bo eksperymentowałem z CascadeType.ALL i CascadeType.PERSIST a nie sprawdziłem do czego służą i nie pomyślałem żeby całkowicie ją usunąć. Dzięki.

http://stackoverflow.com/questions/23645091/spring-data-jpa-and-hibernate-detached-entity-passed-to-persist-on-manytomany-re

0

Poczytaj o tym...
http://howtodoinjava.com/hibernate/hibernate-jpa-cascade-types/

zastanów się czasem czy nie chcesz... wyszukiwać najpierw roli... żeby przypisać ją do usera?
dalej robisz to przez new Role()?

0

A jak chcesz się czegoś nauczyć to napisz testy do tego.
Kilka scenariuszy, z wieloma kilkoma rolami.

Nie zdziwi mnie jeśli Ci jakiś nie przejdzie.

0
Krzywy pomidor napisał(a):

zastanów się czasem czy nie chcesz... wyszukiwać najpierw roli... żeby przypisać ją do usera?
dalej robisz to przez new Role()?

Tak, wyszukuję najpierw rolę w serwisie. Tak to wygląda:

   @Override
    public void save(User user) {
        Set<Role> roles = new HashSet<>();
        Role role = roleService.findByName("USER");
        roles.add(role);
        user.setRoles(roles);
	...
0

Lepiej.
Ale polecam Guave.

user.setRoles(Sets.newHashSet(roleRepository.findByNameIgnoreCase(("user")));

RoleService to JpaRepository? Tak?

0

Nie, interfejsy repozytoriów dziedziczą JpaRepository. Nie trzeba nic implementować 'ręcznie'.

public interface RoleRepository extends JpaRepository<Role, Integer> {
    
    Role findByName(String name);
    
}
0

Tak wiem do czego są repozytoria. Tak chodziło mi o repozytoria rozszerzające JpaRepository.

To po co Ci roleService.findByName("user") ?

I napisz testy.

0

Masz na myśli to dlaczego korzystam z serwisu a nie bezpośrednio z repozytorium? Nie wiem. Żeby mieć trochę porządku w kodzie? Chyba że jest z tym coś nie tak?

I napisz testy.

Napiszę.

0
Szczypiorek napisał(a):

Masz na myśli to dlaczego korzystam z serwisu a nie bezpośrednio z repozytorium? Nie wiem. Żeby mieć trochę porządku w kodzie? Chyba że jest z tym coś nie tak?

Nie znam struktury. Musiałbyś mi pokazać.

Serwis raczej powinien robić ogólne zmiany na encjach, create, update, delete itp.

Jesli robisz metode w serwisie, w której wywołujesz repozytorium tylko po to by zrobić findByName to jest to dla mnie bez sensu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1