#Hibernate doesn't save a list of authorities of a user to table as separate rows. It saves only one.

41 messages · Page 1 of 1 (latest)

modest mango
#

I need help to save several roles of a user to database. Using Spring Boot JPA. User can have many roles. A role belongs to one user. I tried to create three users - an admin, a user and a manager. Admin has admin role, user has user role. Manager has both - admin and user roles.
I have Authority class that has a role. The problem is that for the manager hibernate creates only last role - USER. And I expected that it will have both roles. In database I see that manager has only 1 row. And it should have 2 rows. What am I doing wrong?
User:

@Entity
@Table(uniqueConstraints= {@UniqueConstraint(columnNames="username")}, name = "Users")
public class User implements UserDetails{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @NonNull
    private String username;
    @NonNull
    private String password;
    @NonNull
    private String email;
    @OneToMany(mappedBy = "user")
    private List<Authority> authorities = new ArrayList<>();
//...

Authority:

@Entity
public class Authority implements GrantedAuthority {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Enumerated(EnumType.STRING)
    private Role authority;
    @JsonIgnore
    @ManyToOne(optional = false)
    private User user;
//...
alpine zincBOT
#

This post has been reserved for your question.

Hey @modest mango! Please use /close or the Close Post button above when you're finished. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.

TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.

modest mango
#

Creating users:

    @PostConstruct
    public void addFirstUser() throws Exception {

        if (userDao.findUsersByAuthority(Role.ADMIN).size() == 0) {
            List<String> adminRole = new ArrayList<>();
            List<String> userRole = new ArrayList<>();
            List<String> managersRoles = new ArrayList<>();
            //public UserDTO(List<String> roles, String email, String username, String password)
            adminRole.add("ADMIN");
            UserDTO firstAdmin = new UserDTO(adminRole, "admin@admin.lt", "admin@admin.lt","admin@admin.lt");

            userRole.add("USER");
            UserDTO firstUser = new UserDTO(userRole, "user@user.lt", "user@user.lt", "user@user.lt");
            
            managersRoles.add("ADMIN");
            managersRoles.add("USER");
            UserDTO firstManager = new UserDTO(managersRoles, "manager@manager.lt", "manager@manager.lt", "manager@manager.lt");

            userService.createUser(firstAdmin);
            userService.createUser(firstUser);
            userService.createUser(firstManager);
        }
        else LOG.info("There already exist users which Role is - {}", Role.ADMIN.toString());
    }
#

Database:

#

Creating Users service:

#
    @Transactional
    public User createUser(UserDTO userData) {
        User newUser = new User();

        newUser.setEmail(userData.getEmail());
        List<Authority> authority = new ArrayList<>();
        Authority auth = new Authority();
        for(String str : userData.getRoles()) {
            auth.setAuthority(Role.valueOf(str));
            authority.add(auth);
        }    
        newUser.setAuthorities(authority);
        newUser.setUsername(userData.getUsername());
        newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));
        User returnUser = userRepo.save(newUser);
        for(Authority role : authority) {
            role.setUser(returnUser);
            authRepo.save(role);
        }
        return returnUser;
    }
#

QUESTION: Why the manager in the database has only 1 USER authority instead of two? I added 2 roles for him - admin and user. But in the DB it has only user. What I was doing wrong?

lofty minnow
#

@modest mango What is your database?

modest mango
#

MariaDB

#

HeidiSql is its Windows client

lofty minnow
#

Are you working from a fresh database everytime? Like why not just seed the database with your users and such

modest mango
#

I think the database is fresh. It runs in the memory since the boot up.

#

I don't seed database manually

#

I need that Spring would add users the way I defined

#

because React.js will send data from website and spring will have to work like a charm

#

Maybe the way I add role is not right?

#
    User returnUser = userRepo.save(newUser);
        for(Authority role : authority) {
            role.setUser(returnUser);
            authRepo.save(role);
        }
#

Maybe this operation is immutable?

#

single

#

repo save

#

can I run it in loop

lofty minnow
#

You can run it in a loop

#
        User newUser = new User();

        newUser.setEmail(userData.getEmail());
        newUser.setUsername(userData.getUsername());
        newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));

        List<Authority> authorities = new ArrayList<>();
        for(String str : userData.getRoles()) {
            Authority auth = new Authority();
            auth.setAuthority(Role.valueOf(str));
            auth.setUser(newUser);
            authority.add(auth);
        }    
        newUser.setAuthorities(authority);
        return userRepo.save(newUser);

Try that?

#

Wait I'm dumb, auth is being reused

modest mango
#

edit

lofty minnow
#

You need to put the new Authority() into the for loop, otherwise you're using the same object

modest mango
#

mm.. ok lets see

#

I thought we can edit the same object and just to change its property

lofty minnow
#

No, you want new objects

#

Each object represents a row in the database, so when you mutated the same object, you were changing what was going to be saved.

modest mango
#

@lofty minnow With your function code hibernate does not save Authorities. Only Users. But I understood idea that I need to create new Authority objects in order to add new row to the table. The service code to create new user is this:

    @Transactional
    public User createUser(UserDTO userData) {
        User newUser = new User();
        
        newUser.setEmail(userData.getEmail());
        List<Authority> authority = new ArrayList<>();
        for(String str : userData.getRoles()) {
            Authority auth = new Authority();
            auth.setAuthority(Role.valueOf(str));
            authority.add(auth);
        }    
        newUser.setAuthorities(authority);
        newUser.setUsername(userData.getUsername());
        newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));
        User returnUser = userRepo.save(newUser);
        for(Authority role : authority) {
            role.setUser(returnUser);
            authRepo.save(role);
        }
        return returnUser;
}

First you have to save new user and get its object from database. It will have user id. then to use returned object to create his authorities and add to auth Repository.

#

result:

#

Manager id 25.

lofty minnow
#

I'm surprised my code didn't work, but I'm glad the change fixed it

modest mango
#

Authority table now has 2 rows with constraint column values 25

#

Thank you.

alpine zincBOT
# modest mango Thank you.

If you are finished with your post, please close it.
If you are not, please ignore this message.
Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.