Search code examples
javajpaspring-data-jpathymeleaf

setting value of thymeleaf from field which have 1:N relationship. What should I do?


The relationship between classes is 1:N. In Thymeleaf, I created a split form object to submit form data. But when I press send, it sends, but I don't see any data on the screen.

Professor.class

@Entity
@Getter
@Setter
@Table(name = "professor")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "username", "userid", "position", "sal", "hiredate"})
public class Professor {

    @Id @GeneratedValue
    @Column(name = "profno", nullable = false)
    private Long id;

    @Column(name = "name", nullable = false, length = 50)
    private String username;

    @Column(nullable = false, length = 50)
    private String userid;

    @Column(nullable = false, length = 20)
    private String position;

    private int sal;

    private String hiredate;

    private int comm;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "deptno")
    private Department department;

    @OneToMany(mappedBy = "professor")
    private List<Student> students = new ArrayList<>();

    public Professor(String username) {
        this.username = username;
    }

    public Professor(String username, String position) {
        this.username = username;
        this.position = position;
    }

    public Professor(String username, String position, int sal, String hiredate, int comm, String userid, Department department) {
        this.username = username;
        this.hiredate = hiredate;
        this.userid = userid;
        this.sal = sal;
        this.comm = comm;
        this.position = position;
        if (department != null) {
            setDepartment(department);
        }
    }

    // ===== Method ===== //
    public void setDepartment(Department department) {
        this.department = department;
        department.getProfessors().add(this);
    }

Department.class

@Entity
@Getter
@Setter
@Table(name = "department")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "name", "loc"})
public class Department {

    @Id @GeneratedValue
    @Column(name = "deptno", nullable = false)
    private Long id;

    @Column(name = "dname", length = 100)
    private String name;

    @Column(length = 100)
    private String loc;

    @OneToMany(mappedBy = "department")
    private List<Professor> professors = new ArrayList<>();

    @OneToMany(mappedBy = "department")
    private List<Student> students = new ArrayList<>();
    
    public Department(String name) {
        this.name = name;
    }

    public Department(String name, String loc) {
        this.name = name;
        this.loc = loc;
    }
}

ProfessorForm.class

@Getter
@Setter
public class ProfessorForm {

    private Long id;

    @NotEmpty()
    private String username;
    private String userid;
    private String position;
    private String hiredate;
    private int sal;
    private int comm;
    private Department department;
}

Controller.class

Professor professor = new Professor(form.getUsername(), form.getUserid(),
                form.getComm(), form.getHiredate(), form.getSal(), form.getPosition(), form.getDepartment());

Thymeleaf

    <form th:action="@{/professor/add}" th:object="${professorForm}" method="post">
        <div class="form-group">
            <label th:for="username">name</label>
            <input type="text" th:field="*{username}" class="form-control" placeholder="">
        </div>

        <div class="form-group">
            <label th:for="userid">id</label>
            <input type="text" th:field="*{userid}" class="form-control" placeholder="">
        </div>

        <div class="form-group">
            <label th:for="position">position</label>
            <input type="text" th:field="*{position}" class="form-control" placeholder="">
        </div>

        <div class="form-group">
            <label th:for="sal">sal</label>
            <input type="number" th:field="*{sal}" class="form-control" placeholder="">
        </div>

        <div class="form-group">
            <label th:for="hiredate">hiredate</label>
            <input type="date" th:field="*{hiredate}" class="form-control" placeholder="">
        </div>

        <div class="form-group">
            <label th:for="comm">comm</label>
            <input type="range" th:field="*{comm}" class="form-control" min="0" max="100" value="0" placeholder="">
        </div>

        <div class="form-group">
            <label th:for="departmentId">loc</label>
            <input type="text" th:field="*{department.loc}" class="form-control" placeholder="">
        </div>

At the end, it is confirmed that department.loc is the problem. How should we deal with this?


Solution

  • I assume you want to user of the HTML form to select a certain department for the to-be-created professor entity. The easiest way to support this is adding a HTML select that shows all possible departments, allowing the user to select one.

    To make this possible with Thymeleaf, you need the following:

    1. Update ProfessorForm to use the primary key of the entity that should be referenced (Department in this case, so use long):
    public class ProfessorForm {
    
       // instead of: private Department department;
        private long departmentId;
    }
    
    1. in the @GetMapping controller method, return all department names and id's. This is needed to fill up the HTML select
    List<DepartmentNameAndId> departments = ...
    model.addAttribute( "departments", departments);
    
    1. Update the Thymeleaf template to use a HTML select:
    <select th:field="*{departmentId}">
                <option th:each="department : ${departments}"
                        th:text="${department.name}"
                        th:value="${department.id}">
            </select>
    
    1. In de @PostMapping in the controller, use the departmentId to get the corresponding Department object and use that to create the Professor object.

    See Using HTML select options with Thymeleaf for some more details.