Search code examples
spring-mvcthymeleaf

Thymeleaf accessing nested objects


Can someone please assist on the below? I have an order Object and Item object where there is a many to many relation, I want to iterate through the items of an Order and preview them on the web, below you can see the models and controller(using spring MVC) can someone guide me to how this can be done, I searched a lot but not able to find the proper way.

Error getting

Error I'm getting is: Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'id' cannot be found on object of type 'org.hibernate.collection.internal.PersistentSet' - maybe not public or not valid?

My entity class is

    @Entity
    public class OrderDetail extends Order{

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

    private String branchCode;
    private String ord;
    private String eiclientNumber;
    private String clientOrderNumber;
    private String consigneeP;
    private String paymentTerms;
    private String earliestShipDate;
    private String latestShipDate;
    private String consigneeCode;
    private String billToCode;
    private String thirdPartyBillToCustomerNo;
    private String preferredCarrier;
    private String usd1;
    private String usd2;

    @ManyToMany(mappedBy = "orderDetails")
    private Set<ItemDetail>  itemDetails = new HashSet<>();

}

And another one is

  @Entity
    public class ItemDetail extends Order{

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

    private String branchCode;
    private String ordNo;
    private String detail;
    private String lineNumber;
    private String skuNumber;
    private String qty;
    private String lotNo;
    private String receiptPo;
    private String usd1;
    private String usd2;
    private String usd3;
    private String usd4;


    @ManyToMany
    @JoinTable(name = "order_item", joinColumns = @JoinColumn(name = "item_id"), inverseJoinColumns = @JoinColumn(name = "order_id"))
    private Set<OrderDetail> orderDetails = new HashSet<>();
 }

And this is the method of my controller

@RequestMapping("orders/items")
   public String listItems(Model model){

   List<OrderDetail>  orderDetails = new ArrayList<>();
    orderDetails = orderService.listAll();
    model.addAttribute("items",orderDetails);

    return "orders/items";
}

And my html code is

<table class="table table-hover ">
                            <thead class="thead-inverse">
                                <tr>
                                    <th>ID</th>
                                    <th>Branch Code</th>
                                   <!-- <th>Ord No</th>
                                    <th>Detail</th>-->
                                    <th>Line Number</th>
                                    <!--<th>SKU Number</th>
                                    <th>Qty</th>
                                    <th>Lot No</th>
                                    <th>Receipt Po</th>
                                    <th>USD1</th>
                                    <th>USD2</th>
                                    <th>USD3</th>
                                    <th>USD4</th>-->
                                </tr>
                            </thead>
                                <tr th:each="item : ${orders.itemDetails}">
                                    <td th:text="${item.id}">123</td>
                                    <td th:text="${item.branchCode}">BEY</td>
                                    <!--<td th:text="${item.ordNo}">G012345</td>
                                    <td th:text="${item.detail}">PO123</td>-->
                                    <td th:text="${item.lineNumber}">123</td>
                                    <!--<td th:text="${item.skuNumber}">SKU123</td>
                                    <td th:text="${item.qty}">25</td>
                                    <td th:text="${item.receiptPo}">PO123</td>
                                    <td th:text="${item.usd1}">123</td>
                                    <td th:text="${item.usd2}">1234</td>
                                    <td th:text="${item.usd3}">123456789</td>
                                    <td th:text="${item.usd4}">123456789</td>-->

                                </tr>
                        </table>

Solution

  • First of all work on your design. You are sending entity object to the view, which is not recommended. Bind the DTO object with the view.

    REGARDING THE NESTED ITERATION: Lets say we have an Order object which has a list of OrderDetail obejct (in your case set of OrderDetail)

    We are adding a list of Order object to the model. We want to iterate this Order list and the list of OrderDetail that each order has. The thymeleaf snippet would be like following

        <tr>
            <th>OrderId</th>
            <th>OrderDescription</th>
            <th>Details</th>
        </tr>
        <tr th:each="order : ${orders}" th:id="'order' + ${order.id}">
            <td th:text="${order.id}">id</td>
            <td th:text="${order.description}">description</td>
            <td>
                <table>
                    <tr>
                        <th>DetailId</th>
                        <th>DetailDescription</th>
                    </tr>
                    <tr th:each="detail: ${order.details}">
                        <td th:text="${detail.id}">id</td>
                        <td th:text="${detail.description}">description</td>
                    </tr>
                </table>
            </td>
        </tr>
    

    And the output would be like following.

    enter image description here