Search code examples
javaspring-bootthymeleaf

Problem in iterating list of self referencing entities (Spring Boot + Thymeleaf)


I'm developing an e-commerce application and I have a Category class and an Item class among others. Category is self-referencing as it is supposed to handle subcategories as well. Now I'm trying to make a select element iterating through all categories, but my brain just cant figure out how to do this. It may be that my way of thinking about categories is all wrong and the whole logic needs to be re-evaluated.. comment are more than welcome on that level too!

Class Item:

@Entity
@NoArgsConstructor
@Getter
@Setter
@ToString
public class Item implements Serializable, Comparable<Item> {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    private ItemType itemType;

    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "category")
    private Category category;

        ... Unrelated object properties etc.
}

Class Category:

@Entity
@NoArgsConstructor
@Data
public class Category extends AbstractPersistable<Long> {

    @NotNull
    private String name;

    @JsonBackReference
    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "parentCategory")
    private Category parentCategory;

    @OneToMany(mappedBy = "parentCategory")
    private List<Category> subCategories = new ArrayList<>();

    @LazyCollection(LazyCollectionOption.FALSE)
    @OneToMany(mappedBy = "category")
    private List<Item> items = new ArrayList<>();
    
    public Category(String name) {
        
        this.name = name;
    }
    
    public Category(String name, Category parent) {
        
        this.name = name;
        
        this.parentCategory = parent;
    }

}

List of categories added to model:

model.addAttribute("categories", categoryRepository.findAll());

Thymeleaf:

<select class="form-control" id="category" name="category">
    <option>All</option>
    <div th:each="category : ${categories}">
        <option class="optionGroup"  th:text="${category.name}" th:value="${category.id}"></option>
        <option  class="optionChild" th:each="subCategory : ${category.subCategories}"  th:text="${subCategory.name}" th:value="${subCategory.id}"></option>
    </div>
</select>

Shows up as:

turns out like this:

The idea offcourse is to show child categories under parent categories (Drink > Alcohol > Beer etc.) Now, I'm not sure how to think about this. Maybe the fix lies in JPARepository queries. Maybe I shoul not use findAll() but something custom. Anyway I have to deal with that issue, when I want to find Items based on their category: how to include child categories to the results of a query?

Ps. I'm not using optgroup because I want also the parent categories to be choosable.

Thank you in advance!


Solution

  • Thanks to xerx593 advice in getting the "main categorien" from the database as the starting point, I ended up with a solution with thymeleaf, that is not beautiful and has still some problems. But the iteration works like this at least somehow: A solution as a question :)