Question: Spring boot + JPA problem with post mapping form where is select multiple

I have a PostMapping whith form where user can create a meeting and invite employees. My problem is that the employees are not saved to the database.
Here is my MeetingDTO:
@Data
@Builder
public class MeetingDto {
    private Long id;
    @NotEmpty(message = "Content could not be empty")
    private String contentOfMeeting;
    @FutureOrPresent
    private LocalDateTime startOfMeeting;
    private LocalDateTime endOfMeeting;
    private Status status;
    private List<Employee> employees;
    private Visitor visitor;
}

Here is my controller:
@GetMapping("/visitors/new-meeting")
    public String createMeetingForm(Model model) {
        List<Employee> employeeList = employeeRepository.findAll();
        model.addAttribute("employeeList", employeeList);
        model.addAttribute("meeting", new Meeting());
        return "visitors-createAMeeting";
    }

    @PostMapping("/visitors/new-meeting")
    public String saveMeeting(@ModelAttribute("meeting") MeetingDto meetingDto) {
        String nameOfVisitor;

        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof UserDetails) {
            nameOfVisitor = ((UserDetails)principal).getUsername();
        } else {
            nameOfVisitor = principal.toString();
        }

        Long visitorId = visitorRepository.findByEmailAddress(nameOfVisitor).getId();
        meetingDto.setVisitor(visitorRepository.findById(visitorId).orElse(null));
        meetingService.createMeeting(visitorId, meetingDto);
        return "redirect:/visitors/home";
    }

ServiceImpl:
@Service
public class MeetingServiceImpl implements MeetingService {
    private MeetingRepository meetingRepository;
    private EmployeeRepository employeeRepository;
    private VisitorRepository visitorRepository;

    @Autowired
    public MeetingServiceImpl(MeetingRepository meetingRepository, EmployeeRepository employeeRepository,
                              VisitorRepository visitorRepository) {
        this.meetingRepository = meetingRepository;
        this.employeeRepository = employeeRepository;
        this.visitorRepository = visitorRepository;
    }

    private Meeting mapToMeeting(MeetingDto meetingDto) {
        return Meeting.builder()
                .id(meetingDto.getId())
                .contentOfMeeting(meetingDto.getContentOfMeeting())
                .startOfMeeting(meetingDto.getStartOfMeeting())
                .endOfMeeting(meetingDto.getEndOfMeeting())
                .status(Status.valueOf(String.valueOf(Status.REJECTED)))
                .employees(meetingDto.getEmployees())
                .build();
    }

    @Override
    public void createMeeting(Long visitorId, MeetingDto meetingDto) {
        Visitor visitor = visitorRepository.findById(visitorId).orElse(null);
        Meeting meeting = mapToMeeting(meetingDto);
        meeting.setVisitor(visitor);
        meeting.setEmployees(meetingDto.getEmployees());
        meetingRepository.save(meeting);
    }
}

And my template for GetMapping:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>Create a meeting</title>
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l"
          crossorigin="anonymous" />
</head>
<body>
<div class="container">
    <h3>Create a meeting</h3>
    <hr/>
    <form action="#" th:action="@{/visitors/new-meeting}" th:object="${meeting}" method="post">
        <p>Content: <input type="text" id="content" name="content" th:field="*{contentOfMeeting}" placeholder="Content"></p>
        <p th:if="${#fields.hasErrors('contentOfMeeting')}" class="text-danger" th:errors="*{contentOfMeeting}"></p>
        <p>Start of meeting: <input type="datetime-local" id="start" name="start" th:field="*{startOfMeeting}" placeholder="Start of meeting"></p>
        <p th:if="${#fields.hasErrors('startOfMeeting')}" class="text-danger" th:errors="*{startOfMeeting}"></p>
        <p>End of meeting: <input type="datetime-local" id="end" name="email" th:field="*{endOfMeeting}" placeholder="End of meeting"></p>
        <p></pd><span th:if="${#fields.hasErrors('endOfMeeting')}" th:errors="*{endOfMeeting}" class="text-danger">End of meeting can not be before start of meeting</span></p>
        <label>Employees: </label>
        <p>To select more than one employee please click ctrl</p>
        <select id="employee" class="form-control" th:field="${employeeList}" multiple name="employeeList">
            <option th:each="employee : ${employeeList}" th:value="${employee.id}" th:text="${employee.name + ' ' + employee.surname}"></option>
        </select>
        <br>
        <p><input type="submit" value="Submit"/></p>
        <br>
        <h6><a th:href="@{/logout}">Logout</a></h6>
        <br>
    </form>
</div>
</body>
</html>

Could you be so kind to take a look and help me to solve the issue?
I tried refactor template and controller but the problem still exist.


Answer:
While reviewing your code, I noticed a potential issue with how the relationships are handled in JPA/Hibernate. When you're dealing with related entities, in this case Meeting and Employee, it's crucial to manage both sides of the relationship correctly.
In your code, you're assigning employees to a meeting using meeting.setEmployees(meetingDto.getEmployees());. This is correct, but depending on your relationship setup, it may not be sufficient. You might also need to set the meeting to each employee. For example, you could iterate over each employee and add the meeting:
List<Employee> employees = meetingDto.getEmployees();
for(Employee employee : employees) {
    employee.getMeetings().add(meeting); // Assumes a getMeetings() method in Employee class
}

This snippet adds the current meeting to the list of meetings for each employee. When you save your meeting, the related employees should also be updated.
Of course, this suggestion is based on common practice when using JPA/Hibernate, and the specific implementation may need adjustment according to your actual entity configuration. It's important to ensure the relationship between Meeting and Employee entities is set correctly, with appropriate cascading settings. You might need to set CascadeType.PERSIST or CascadeType.MERGE to make sure the changes to the employees are stored when saving the meeting.
If the problem persists, it would be helpful to take a closer look at the parts of your Employee and Meeting entities that define their relationship. This would allow for a more precise solution to your problem.
Revised Answer
The challenge seems in correctly assigning only the selected employees to the meeting, rather than all the employees as currently happens.
From the look of your form, it seems likely that only the IDs of the selected employees are being sent to the server when the form is submitted. So, we should adjust your MeetingDto to hold a list of these IDs. Here's how:
public class MeetingDto {
    // Other fields...
    private List<Long> employeeIds; // Replaced from List<Employee> employees
    // Remaining fields...
}

Next, we can modify the createMeeting method within your MeetingService to handle these employee IDs:
@Override
public void createMeeting(Long visitorId, MeetingDto meetingDto) {
    Visitor visitor = visitorRepository.findById(visitorId).orElse(null);
    Meeting meeting = mapToMeeting(meetingDto);
    meeting.setVisitor(visitor);

    List<Employee> selectedEmployees = employeeRepository.findAllById(meetingDto.getEmployeeIds()); // Retrieve employees by their IDs
    meeting.setEmployees(selectedEmployees); 

    meetingRepository.save(meeting);
}

Lastly, we need to ensure your form is sending the IDs of the selected employees. Your select element in the form should be modified to look like this:
<select id="employee" class="form-control" th:field="*{employees}" multiple name="employeeList">
    <option th:each="employee : ${employeeList}" th:value="${employee.id}" th:text="${employee.name + ' ' + employee.surname}"></option>
</select>

With these alterations, your form will be transmitting the IDs of the selected employees to the server. Then, your service can retrieve the relevant employees based on these IDs from the database. As a result, only the selected employees will be associated with the meeting.