grid not displaying ManyToMany rs data

I made a small project using Vaadin Flow (23), Springboot and MySQL. It has 2 entities: Ticket and Employee. It contains a @ManyToMany mapping (i.e. many tickets can have many employees assigned to it, or, many employees can be assigned to many tickets).

// Code snippet of Ticket.java's @ManyToMany mapping
@ManyToMany
    @JoinTable(
            name = "tickets",
            joinColumns = { @JoinColumn(name = "ticketId")},
            inverseJoinColumns = { @JoinColumn(name = "employeeId")}
    )
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Employee> employees;

// Code snippet of Employee.java's @ManyToMany mapping
@ManyToMany(mappedBy = "employees")
    @Fetch(FetchMode.SELECT)
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Ticket> tickets;

I was able to set up and populate 2 grids Grid & Grid successfully (using the repos and service layers .findAll() method to populate the grids with all the employees and all the tickets stored in the database). Build and run the project, and both grids render on the screen successfully.

However, when adding a third grid of Grid ticketsAssignedToEmployeeX, which should display the list of tickets assigned to a specified employee, my whole application crashes and nothing renders on the screen.

I cannot figure out why my grid displaying info from my ManyToMany mapped table in the database crashes my project and will not render onto the screen. I can access the data from the ManyToMany table and place it in a span, but it refuses to render the same data in a grid. Any help would be appreciated.

Code is below:

Grid<Ticket> ticketsAssignedToEmployeeX = new Grid<>(Ticket.class);
...
// currently hard coding employeeXId in my code to an acutal employee's id from my DB
ticketsAssignedToEmployeeX.setItems(service.getTicketsAssignedToEmployee(employeeXId));
add(ticketsAssignedToEmployeeX); // will not render anything on my screen.

I get this error msg when my database is set to create-drop "Error executing DDL "alter table events drop foreign key FKg0mkvgsqn8584qoql6a2rxheq" via JDBC Statement"

Also, my database is very small currently. Only 10 employees and 4 tickets stored in the database. Each ticket is assigned to 2 employees.

It sounds like the issue is with how you are using JPA, can you share your entities and relevant code that you use to fetch those assigned tickets

sure thing!

Ticket Entity

@Entity
@Data
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Ticket {
    @Id
    @GeneratedValue
    @Column(name = "ticketId")
    private Long id;
    @Override
    public int hashCode() {
        if (id != null) {
            return id.hashCode();
        }
        return super.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof AbstractEntity)) {
            return false; // null or other class
        }
        AbstractEntity other = (AbstractEntity) obj;

        if (id != null) {
            return id.equals(other.getId());
        }
        return super.equals(other);
    }

    public Ticket(String name, List<Employee> employees) {
        this.name = name;
        this.employees = employees;
    }

    @NotNull
    private String name;

    public Ticket(String name) {
        this.name = name;
    }

    // M:N rs here
    @ManyToMany
    @JoinTable(
            name = "tickets",
            joinColumns = { @JoinColumn(name = "ticketId")},
            inverseJoinColumns = { @JoinColumn(name = "employeeId")}
    )
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Employee> employees;
}

Employee Entity

@Entity
@Data
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    @Id
    @GeneratedValue
    @Column(name = "employeeId")
    private Long id;
    @Override
    public int hashCode() {
        if (id != null) {
            return id.hashCode();
        }
        return super.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof AbstractEntity)) {
            return false; // null or other class
        }
        AbstractEntity other = (AbstractEntity) obj;

        if (id != null) {
            return id.equals(other.getId());
        }
        return super.equals(other);
    }

    @NotEmpty
    private String firstName = "";

    @NotEmpty
    private String lastName = "";

    private String fullName;

    public Employee(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    // get custom fullname
    public String getFullName() {
        return (firstName + " " + lastName);
    }

    // M:N rs here
    @ManyToMany(mappedBy = "employees")
    @Fetch(FetchMode.SELECT)
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<Ticket> tickets;
}

Ticket Repo:

public interface TicketRepo extends JpaRepository<Ticket, Long> {
    List<Ticket> findTicketsByEmployeesId(Long id);
    Optional<Ticket> findById(Long id);
}

Employee Repo:

public interface EmployeeRepo extends JpaRepository<Employee, Long> {
    Optional<Employee> findById(Long id);
}

Service class:

@Service
@AllArgsConstructor
public class TicketService {
    TicketRepo ticketRepo;
    EmployeeRepo employeeRepo;

    public long countTickets(){ return ticketRepo.count();}
    public void saveTicket(Ticket ticket){ticketRepo.save(ticket);}
    public void deleteTicket(Ticket ticket){ticketRepo.delete(ticket);}
    public List<Ticket> findAllTickets() {return ticketRepo.findAll();}

    public long countEmployees(){ return employeeRepo.count();}
    public void saveEmployee(Employee employee){employeeRepo.save(employee);}
    public void deleteEmployee(Employee employee){employeeRepo.delete(employee);}
    public List<Employee> findAllEmployees() {return employeeRepo.findAll();}

    public Optional<Employee> findById(Long id){
        Optional<Employee> e = employeeRepo.findById(id);
        return e;
    }

    public List<Ticket> getTicketsAssignedToEmployee(Long id){ 
        return ticketRepo.findTicketsByEmployeesId(id);
    }
}

the view where I am trying to call the grid:

@PageTitle("Tree Grid Test")
@Route(value="gridTest")
public class ListView extends VerticalLayout {
Grid<Ticket> ticketsAssignedToEmployeeX = new Grid<>(Ticket.class);
TicketService ticketService;
public ListView(TicketService ticketService) {
        this.ticketService = ticketService;
        Long employeeXId = 2L;
        setSizeFull();

// use service layer to retrieve tickets assigned to employeeX
ticketsAssignedToEmployeeX.setItems(ticketService.getTicketsAssignedToEmployee(employeeXId));
ticketsAssignedToEmployeeX.setSizeFull();

add(ticketsAssignedToEmployeeX);
}
}

This is the error msg I get

java.lang.StackOverflowError: null

This is the sample data i put into the ticket (table name = ticket)
ticket.png

This is the sample data i put for the employee (table name = employee)
employee.png

This is the ManyToMany intermediary table (table name = tickets) storing all the ticket_id to the assigned employee_id
tickets.png

if anyone has any idea of how I could fix this, it would really be appreciated :slightly_smiling_face: Been working on this for a while but still have not figure out a solution T_T