1

I'm very new to Java Spring and I'm trying for a few days to get my relationship working, but it doesn't. I'm using Java Spring and Mysql.

The Admin should add Employees to the database. The Employees will only see specific data. My problem is, that I don't understand how I can make a right POST request from the EmployeesController and get the user_id from the User Model. I tried some different implementations, but I still cannot get it to work.

I have an entity for Users, Roles and Employees. An employee is always a user, but a user may not be an employee. So my database structure is as follows:

users:

+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(30)  | NO   |     | NULL    |                |
| email    | varchar(100) | NO   |     | NULL    |                |
| password | varchar(100) | NO   |     | NULL    |              
+----------+--------------+------+-----+---------+----------------+

employees:

+-------------------+--------------+------+-----+---------+----------------+
| Field             | Type         | Null | Key | Default | Extra          |
+-------------------+--------------+------+-----+---------+----------------+
| id                | int          | NO   | PRI | NULL    | auto_increment |
| academic_title    | varchar(100) | NO   |     | NULL    |                |
| department        | varchar(100) | NO   |     | NULL    |                |
| user_id           | int          | NO   |     | NULL    |                |
+-------------------+--------------+------+-----+---------+----------------+

Only an admin can add an employee to the system, the employees can only log in and see some data. So like I understand in Java Spring parameters like user_id in employees table are not extra written in the model. So this is what I have right now:

Employee.java

@Entity
@Table(name = "employees")
public class Employee{
  
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

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

    @Size(min=3, max = 100)
    private String academic_title;

    @Size(min=3, max = 100)
    private String department;

    public Employee() {}
 
    public Employee(String academic_title, String department) {
        super();
        this.academic_title = academic_title;
        this.department = department;
    }
    
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }

    public String getDepartment() {
        return department;
    }
 
    public void setDepartment(String department) {
        this.department = department;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

User.java

@Entity
@Table(name = "users")
public class User{
  @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
  
    @NotBlank
    @Size(min=3, max = 50)
    private String username;
 
    @NaturalId
    @NotBlank
    @Size(max = 50)
    @Email
    private String email;
 
    @NotBlank
    @Size(min=6, max = 100)
    private String password;
 
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_roles", 
      joinColumns = @JoinColumn(name = "user_id"), 
      inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();

    @OneToOne(fetch = FetchType.LAZY,
            cascade =  CascadeType.ALL,
            mappedBy = "user")
    private Employee employee;
 
    public User() {}
 
    public User(String username, String email, String password) {
        super();
        this.username = username;
        this.email = email;
        this.password = password;
    }
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public Set<Role> getRoles() {
        return roles;
    }
 
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}

EmployeeController.java (create Employee function)

    public Employee createEmployee(@PathVariable (value = "user_id") Long user_id,
                                 @Valid @RequestBody Employee employee) {
                                     
        userRepository.findById(user_id);
        employeeRepository.save(employee);
        return employee;

    }

userRepository.java

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
    Optional<User> findById(Long id);
    Boolean existsByUsername(String username);
    Boolean existsByEmail(String email);
}

My Postman POST request to add employees:

{
    "academic_title": "xy",
    "department": "xx",
    "user_id": 5
}

When I try to save the user_id as a normal Long parameter, I can save it to the database. But then when I fetch the existing employees, the join function doesn't work so I cannot see who user_id 5 is. And when I try it the other way, like the code above I'm getting an error like: not-null property references a null or transient value or something like Employee column: user_id (should be mapped with insert="false" update="false"). So I don't know what to do, I'm stuck in this problem for 5 days.

Thanks in advance for your help!

2 Answers 2

2

If you decided to define your relationship using Hibernate and annotation @OneToOne, you should keep in your mind now Employee has a class property (attribute) User. And for store foreign key from the employee table on the user table you need to set User instance to Employee.

You should try something like this in your case:

public Employee createEmployee(@PathVariable (value = "user_id") Long user_id,
                             @Valid @RequestBody Employee employee) {
                                 
    // find user by id or else throw exception
    User userById = userRepository.findById(user_id).orElseThrow(() -> new 
    RuntimeException("Not found."));
    
    // set user into employee. it's like binding two entities
    employee.setUser(userById);

    // after that you can save your employee entity.
    return employeeRepository.save(employee);
    
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you. But how can I make a relationship without Hibernate? All the examples I saw used Hibernate. I tried the code from you, but I'm still getting this error: not-null property references a null or transient value
You could also use Spring Jdbc or Hibernate or Jooq for mapping your database’s tables to Java’s objects that what I mean.
And what about your error. Check out your json from postman. It contains ‘user_id’, but you declared ‘user_id’ as ‘@PathVariable’ in createEmployee() in code above. You should put that ID in url. Now you’re sending this id in body.
I added @PostMapping("/addemployee"). So do you mean I need to make /addemployee/user_id and then in Postman in JSON user_id: 5? I tried it that way, and it's returning a 404 not found error. I also tried /addemployee/5 but its also returning the same error.
@Rosina you don’t need set user_id: 5 in your json in postman) Just annotate controller’s method this way: @PostMapping(“addemployee/{id}”) and that it. And don’t forget to add your user’s id in url path. You will have something like that in final: localhost:8080/addemployee/5 where 5 is user_id
|
0

the join function doesn't work

the fetch type between User and Employee is Lazy. which means that it does not actually load the user when loading an employee. Instead, it loads them when requested to do so.

So as @Zooger mentioned, you should load the user from database first.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.