List <? Extends Enum>
in DTO properly instead of CSV.List <ChildEntity>
etc. in the Entity, you will either go to get the surrogate key every time you perform an update operation, or insert all the records of ChildEntity. It will be fixed.=> Yes, let's use a compound primary key
For MySQL, for example, such a table
CREATE TABLE parent(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
bar VARCHAR(30) NOT NULL
);
CREATE TABLE parent_child(
parent_id INT NOT NULL,
value_ VARCHAR(30) NOT NULL,
PRIMARY KEY(parent_id, value_),
FOREIGN KEY(parent_id) REFERENCES parent(id)
);
ChildEntity
Since it is a composite primary key, we use @EmbeddedId
, but the reference to the parent entity with @ ManyToOne
should be in the field of the __ outer Entity class instead of the PK class __. [^ 1]
[^ 1]: StackOverflowError occurs during read operation when the PK class has a field for @ ManyToOne
.
By adding @MapsId
together with @ManyToOne
, the ID on the parent table side will be assigned when the parent and child are inserted at the same time. However, in the case of parent update child insert, it doesn't take care of it, so you have to synchronize parent and parentId yourself.
ChildEntity.java
@Entity
@Table(name = "parent_child")
@ToString(exclude = "parent")
@NoArgsConstructor
public class ChildEntity {
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class PK implements Serializable {
@Column(name = "parent_id")
private int parentId;
@Column(name = "value_")
private String value;
}
@EmbeddedId
@Getter
@Setter
private PK pk;
@ManyToOne
@JoinColumn(name = "parent_id", referencedColumnName = "id")
@MapsId("parentId")
@Getter
@Setter
private ParentEntity parent;
public ChildEntity(@NonNull final ParentEntity parent,
@NonNull final String value) {
this.pk = new PK(parent.getId(), value);
this.parent = parent;
}
public void setParent(@NonNull final ParentEntity parent) {
this.pk.setParentId(parent.getId());
this.parent = parent;
}
}
Note that careless use of lombok.ToString, lombok.EqualsAndHashCode, Jackson, etc. will cause an infinite loop because it is a circular reference between parent and child.
ParentEntity
The parent side is no different from the normal @OneToMany
(when using surrogate keys).
ParentEntity.java
@Entity
@Table(name = "parent")
@Data
public class ParentEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToMany(mappedBy = "parent", orphanRemoval = true, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Fetch(FetchMode.SUBSELECT)
private List<ChildEntity> children;
@Column(name = "bar")
private String bar;
}
Note that if you do not set orphanRemoval in the parameter of @ OneToMany
, the child record will not be deleted even if you delete the child on the parent side.
Also, if you do not add @ Fetch (FetchMode.SUBSELECT)
, the N + 1 problem will occur.
Hibernate 5.0.12 looks like this. When inserting the newly added ChildEntity, I am concerned about the fact that each item is selected separately from the List acquired together with ParentEntity. For the elements that haven't changed, EAGER fetch is enough, so I wonder if there is any problem in this project.
select parententi0_.id as id1_0_0_, parententi0_.bar as bar2_0_0_, children1_.parent_id as parent_i1_1_1_, children1_.value_ as value_2_1_1_, children1_.parent_id as parent_i1_1_2_, children1_.value_ as value_2_1_2_ from parent parententi0_ left outer join parent_child children1_ on parententi0_.id=children1_.parent_id where parententi0_.id=?
binding parameter [1] as [INTEGER] - [5]
select childentit0_.parent_id as parent_i1_1_0_, childentit0_.value_ as value_2_1_0_ from parent_child childentit0_ where childentit0_.parent_id=? and childentit0_.value_=?
binding parameter [1] as [INTEGER] - [5]
binding parameter [2] as [VARCHAR] - [0.42733237750132513]
insert into parent_child (parent_id, value_) values (?, ?)
binding parameter [1] as [INTEGER] - [5]
binding parameter [2] as [VARCHAR] - [0.42733237750132513]
delete from parent_child where parent_id=? and value_=?
binding parameter [1] as [INTEGER] - [5]
binding parameter [2] as [VARCHAR] - [0.8694858141499555]
Recommended Posts