0

we would like to implement many-to-many in 3 sperate entity class with Kotlin and SpringBoot. Here is our ERD.

1

We try to follow this tutoial: https://www.baeldung.com/jpa-many-to-many but it will cause a recurse call in our data information.

Here is our Entity class implementation:

@MappedSuperclass
abstract class BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    open val uuid: UUID? = null

    open var updatedAt: Date? = null

    open var createdAt: Date? = null

    @PreUpdate
    fun updateUpdatedAt() {
        this.updatedAt = Date()
    }

    @PrePersist
    fun updateCreatedAt() {
        this.createdAt = Date()
    }
}
@Entity
@Table(name = "student")
open class StudentEntity: BaseEntity() {
    open var name: String? = null

    @OneToMany(mappedBy = "student", fetch = FetchType.EAGER) //EAGER fetch is used to test the data output
    open var attendance: MutableSet<AttendanceEntity> = mutableSetOf()
}
@Entity
@Table(name = "training")
open class TrainingEntity: BaseEntity() {
    open var name: String? = null

    @OneToMany(mappedBy = "training", fetch = FetchType.EAGER) //EAGER fetch is used to test the data output
    open var attendance: MutableSet<AttendanceEntity> = mutableSetOf()
}
@Entity
@Table(name = "attendance")
open class AttendanceEntity: BaseEntity(){
    @ManyToOne
    @JoinColumn(name = "student_id")
    open var student: StudentEntity? = null

    @ManyToOne
    @JoinColumn(name = "training_id")
    open var training: TrainingEntity? = null

    open var time: Date? = null

}

We use trainingRepository.findAll() to query all training for checking and the result:

[
    {
        //training
        "uuid": "ed5e7dd2-ae14-42f4-99d9-588fc2586209",
        "name": "training1"
        "updatedAt": "2022-07-31T09:50:00.000+00:00",
        "attendance": [
            {
                //attendance
                "uuid": "8b35bd45-7ab3-4ef1-af73-83d06ffd7543",
                "time": "2022-07-31T11:42:00.000+00:00",
                "student": {
                    //student
                    "uuid": "b5ae1031-011d-4378-8ae6-6055942e293b",
                    "name": "student1",
                    "attendance": [
                        {   
                            //attendance
                            "uuid": "0a9d5adb-cd7a-4c11-954a-132cbe6fc6eb",
                            "time": "2022-07-31T11:42:00.000+00:00",
                            "student": {
                                "uuid": "b5ae1031-011d-4378-8ae6-6055942e293b",
                                "name": "student1",
                                "attendance": [
                                    //recurse call attendance which we don't want
                                    ...
                                ]
                            }
                            //recurse call student which we don't want
                            ...
                        }
                    ]

                }
            }
        ]
    }
]

The expected result:

[
    {
        //training
        "uuid": "xxxx",
        "name": "training1"
        "updatedAt": "2022-07-31T09:50:00.000+00:00",
        "attendance": [
            {
                //attendance 1
                "uuid": "xxxx",
                "time": "2022-07-31T11:42:00.000+00:00",
                "student": {
                    //student 1
                    "uuid": "xxxx",
                    "name": "student1"
                }
                //attendance 2
                "uuid": "xxxx",
                "time": "2022-07-31T11:42:00.000+00:00",
                "student": {
                    //student 2
                    "uuid": "xxxx",
                    "name": "student2"
                }
                ...
            }
        ]
    }
]

How can we stop the recursion inside the student object class when using the EAGER fetch and what is the best practice of LAZY fetch and when to use it.

Vishal Vasani
  • 647
  • 8
  • 16
  • That doesn't seem to be a problem with JPA but Jackson's JSON marshalling. JPA is quite good in not loading entities it already loaded but Jackson would follow cycles no matter what. You'd need to tell Jackson not to do so e.g. by using a back reference annotation (`@JsonBackReference` I think). – Thomas Aug 11 '22 at 07:36
  • Also note that LAZY fetch wouldn't help here. If Jackson wants to include a reference in the JSON result it will call the corresponding getter which would lead to 1 of 2 results if you used lazy loading for that reference: 1) you're still running inside the transaction that loaded the entity in which case JPA will lazily load the referenced entity or 2) you're not in that transaction anymore in which case you'll get an exception because JPA cannot load the referenced entity. – Thomas Aug 11 '22 at 07:39
  • @Thomas Thanks for your quick response. We are trying on your suggested fix. – RomanJuarez Aug 17 '22 at 04:34

0 Answers0