1

My model has a typical parent-children-relation which is JPA-modelled by an unidirectional @OneToMany relation:
a Parent has 0..n instances of Child (i.e. a List<Child>).

Trying to create and persist an Entity with one dependent Property as follows:

val a_parent = Parent(
        id = "I_am_a_parent",
        children = listOf(Child(kind="childish"))
)
parentRepository.save(a_parent)

surprisingly results in

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [parent_id]; nested exception is 
...
Caused by: org.postgresql.util.PSQLException: 
ERROR: null value in column "parent_id" violates not-null constraint
  Detail: Failing row contains (22, childish, null).

at the line parentRepository.save(a_parent).

Obviously, JPA does not set the id of the parent on the child (column children.parent_id).

Why not? And how to tell it to do so?

The code of Parent and Child is as follows

@Entity
@Table(name = "parents")
data class Parent (
        @Id
        @Column(name = "id")
        var id: String? = null,

        @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true)
        @JoinColumn(name = "parent_id")
        var properties: List<Child> = listOf()
)
@Entity
@Table(name = "children")
data class Child (
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        var id: Int? = null,

        @Column(name = "kind")
        var kind: String? = null
)
Min-Soo Pipefeet
  • 2,208
  • 4
  • 12
  • 31
  • Why do you use nullable `@Id` columns? – Nowhere Man Apr 15 '20 at 16:24
  • @AlexRudenko The column is not nullable, the property is. Because JPA expects a default parameterless constructor. Kotlin generates the parameterless constructor from the default values. I could take 0 or -1 for the default parameter but I prefer `null` as `null` is not a valid value for an id. - But this topic has nothing to do with the error and the problem of the question. – Min-Soo Pipefeet Apr 15 '20 at 19:03

1 Answers1

1

Unidirectional OneToMany may have to be implemented this way (reference):

data class Parent (
  //...
    @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true)
    @JoinColumn(name = "parent_id", nullable = false)
    var properties: List<Child> = listOf()
)

Pay attention to nullable = false if the database column parent_id is not nullable.

Min-Soo Pipefeet
  • 2,208
  • 4
  • 12
  • 31
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
  • You are proposing a bidirectional relation. There are many different ways to implement a parent-children-relationship. I need a unidirectional relation. – Min-Soo Pipefeet Apr 15 '20 at 19:06
  • 1
    Sorry, I overlooked that requirement. Thus, your implementation seems to be quite valid - as described in reference [like this](https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/) However, in such case, the column `parent_id` must be nullable :-\ – Nowhere Man Apr 15 '20 at 21:09
  • That was the right hint. The column `parent_id` doesn't need to be nullable. But if it's not, then a `nullable=false` in my `@JoinColumn` is needed (like given in your answer). So, feel free to edit your answer according to a unidirectional relation and I will vote it up and accept it. – Min-Soo Pipefeet Apr 16 '20 at 17:46
  • Yep. similar issue [had happened before](https://stackoverflow.com/questions/31811989/jpa-unidirectional-onetomany-fails) – Nowhere Man Apr 16 '20 at 18:11