'Kotlin spring ,get ID of entity after saving it

Hello i am new to kotlin world and spring framework. I want to save data to DB in two different tables at same time.

Basically i want to save first the Student(kotlin Class) and right after it i want to save the Student's Id and his teachers id to another table so they can have relation. The front end will send list of teachers id , and the id of the student(only one student). So for each id of teachers i have to make rows in "TeachersToStudent" table and to save the Student to its own table.

       @Entity
         data class Student(
           @javax.persistence.Id
           @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
            val id: Long?,
             var name: String,
    
    )
    
        @Entity
        data class TeachersToStudent(
        @javax.persistence.Id
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Long?,
    
        val studentId: Long,
        val teacherId: Long,    
    
    )

I have tried like this from the controller:

val student =   Student(
            null,
            name
        )

       val result = studentRepo.save(student)
       
        val mutableList = mutableListOf<TeachersToStudent>();
        if ( result.id != null){
            for (item in materialSetIds) {
                mutableList.add((FormulaToMaterialTable(null,result)));
            }
        }

        TeachersToStudentRepo.saveAll(mutableList);

This way the compiler wont work.Gives error :

Smart cast to 'Long' is impossible, because 'result.id' is a property that has open or custom getter

I looked online somewhere it says that saveAndFlush method will give back the id after save but the spring CrudRepository doesn't have this method available in it.

Other sources also suggest to convert after .save() to Integer but this way doesn't work neither.



Solution 1:[1]

The problem here is nullability.?In each entity, the id property is defined as Long?, so it can hold either a long integer, or null.

In practice, I think the annotations will mean that the id always gets assigned a non-null value by the time it's returned from save() and similar methods.?(If there's any problem, they throw an exception; so if they return normally, the ID will have been generated and the entity successfully saved.)

But the compiler doesn't know that!?Neither can it tell whether any other threads could access the entity, so even though you check for null, it can't be certain that the id is still null when you use it in the following lines.

That's what the error message is telling you: it can't smart-cast the nullable Long? to non-nullable Long for you.

In the code you've posted, the most concise solution would be to skip the null check entirely, because you know by then that the ID isn't null.?But that's just shifting the problem; sooner or later, you're bound to need to use the ID.?Then you'd either have to use the !! non-null assertion on it (which is a code smell), or check it.?A safe way to check is to assign it to a temporary variable, and then check that, e.g.:

val resultId = result.id
if (resultId != null) {
    // …Here the compiler knows resultId is not null…
}

(You could use a scoping function such as let() to avoid an explicit temporary variable, but it's still awkward.)

So I'd suggest an alternative solution, which is to make your id non-nullable.?That avoids all these issues.

It's not a perfect solution; you'd need to specify a dummy identifier (e.g. 0 or -1), either when calling the constructor, or as a default value, which is slightly ugly.?But I think that's outweighed by the benefit of avoiding null checks and awkwardness every time you use the ID.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 gidds