Search code examples
hibernatejpaspring-data-jpa

Hibernate unidirectional OneToMany cascade insert failed


Have 2 entities:

Module entity with list of properties

@Entity
@Table(name = "module")
public class ModuleEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "module_id", nullable = false)
private List<PropertyEntity> properties; 

//getters/setters etc
}

Property entity with composite ID

@Entity
@IdClass(PropertyEntityId.class)
@Table(name = "module_property")
public class PropertyEntity {

@Id
@Column(name = "module_id")
private Integer moduleId;

@Id
@Column(name = "[key]")
private String key;

@Column(name = "value")
private String value;

//getters/setters etc
}

With corresponding ID

public class PropertyEntityId implements Serializable {

private Integer moduleId;

private String key;

//getters/setters etc
}

Problem is that when I'm trying to insert Module with Properties list JPA tries to insert module_id twice and second value is null in this case

GenericJDBCException: could not execute statement [The value is not set for the parameter number 4.] [insert into module_property (module_id,value,[key],module_id) values (?,?,?,?)]

What's wrong in my mapping?


Solution

  • You need to replace the moduleId property in the PropertyEntity and PropertyEntityId with the module property:

    @Id
    @ManyToOne
    @JsonBackReference
    @JoinColumn(name = "module_id")
    private ModuleEntity module;
    

    And you should fix the properties field in the ModuleEntity entity:

    @JsonManagedReference
    @OneToMany(mappedBy = "module", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PropertyEntity> properties;
    

    See example 164 in Hibernate ORM User Guide.

    You also need to set a reference to the ModuleEntity instance in each PropertyEntity object that belongs to it. You can do this manually, or use the @JsonManagedReference and @JsonBackReference annotations to have Jackson take care of this for you when deserializing the object.