I'm trying to delete a parent entity that has a one-to-many parent-child relationship using entityManager.remove(parent)
. However, from the SQL log I see OpenJPA calling UPDATE
first and trying to set null for a NOT NULL
field.
executing prepstmnt 773394836 UPDATE child SET parent_id = ? WHERE parent_id = ? [params=(null) null, (long) 16]
executing prepstmnt 1127292223 DELETE FROM parent WHERE id = ? [params=(long) 16]
executing prepstmnt 1297966852 DELETE FROM child WHERE lookup_id = ? AND parent_id = ? [params=(int) 1, (long) 16]
How do I configure my classes to prevent this first UPDATE
call?
My classes:
@Entity
@Table(name = "parent")
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
orphanRemoval = true)
@JoinColumn(name = "parent_id")
private List<Child> children;
// getters, etc.
}
@Entity
@Table(name = "child")
@IdClass(ChildPrimaryKey.class)
public class Child {
@Id
@Column(name = "parent_id", nullable = false, updatable = false)
private long parentId;
@Id
@Column(name = "lookup_id")
private int lookupId;
@ManyToOne
@JoinColumn(name = "parent_id", referencedColumnName = "id",
nullable = false, insertable = false, updatable = false)
private Parent parent;
// getters, etc.
}
My DB tables (in MySQL):
CREATE TABLE IF NOT EXISTS `parent` (
`id` BIGINT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(50) NOT NULL ,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `child` (
`lookup_id` INT NOT NULL ,
`parent_id` BIGINT NOT NULL ,
PRIMARY KEY (`parent_id`, `lookup_id`) ,
INDEX `fk_library_code_idx` (`parent_id` ASC) ,
CONSTRAINT `fk_library_code`
FOREIGN KEY (`parent_id` )
REFERENCES `parent` (`id` )
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
I'm not exactly sure what is causing JPA to decide to execute those queries, however, I do notice a couple of issues with your mappings.
First, you're not specifying the mappedBy
element on your @OneToMany
annotation (i.e. you're not telling OpenJPA that Child
is the owner of the relationship). This would be my first guess as to why you're seeing this behavior. From the API specification:
If the relationship is bidirectional, the mappedBy element must be used to specify the relationship field or property of the entity that is the owner of the relationship.
To fix this, change your Parent
's @OneToMany
to include the mappedBy
element and drop the @JoinColumn
:
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL,
fetch = FetchType.EAGER, orphanRemoval = true)
private List<Child> children;
Additionally, I've noticed you are trying to use Parent
's ID as part of Child
's ID and have two fields on Child
mapping to the same PK column (parent
and parentId
). The preferred way to handle this is with @MapsId
:
@Id
private long parentId;
// ...
@MapsId("parentId")
@ManyToOne
@JoinColumn(name = "parent_id", referencedColumnName = "id", nullable = false)
private Parent parent;