I have implemented a Spring Boot application using Spring Data JPA (and REST) and need to support the entity creation based on uploaded or on-server configuration files. I have created a service with the trigger method annotated using
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
The method is supposed to create a number of entities structurally similar to the following:
@Entity
@Table(name = "T_PARENT")
public class Parent {
@Id
@Column(...)
@GeneratedValue(generator = "customUUID")
UUID id;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT")
@Cascade(CascadeType.ALL)
Collection<Child> children;
}
@Entity
@Table(name = "T_CHILD")
@IdClass(...)
public class Child {
@Id
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "PARENT", nullable = false, updatable = false)
@Cascade(value = { CascadeType.MERGE, CascadeType.DETACH })
Parent parent;
@Id
@Column(name = "NAME", nullable = false, updatable = false)
private String name;
}
There is only a repository for the Parent
(not for the Child
entities). The ID values must be imported so a custom generator is used; this solves a problem similar to the one documented in @Id @GeneratedValue but set own ID value.
This allows saving the parent entity first, then setting a list of children with the parent set to the just created parent (the object returned by parentRepository.save(...)
) and then saving the parent entity again. The @Cascade
annotation is needed in this scenario as one would otherwise run into the issue documented in Spring data jpa detached entity.
If the parent is not saved first, it will cause a PersistentObjectException
with "detached entity passed to persist". If IDs are left to be null
, a single save works.
While this works, it feels like too much work in the service layer. Surely this is something the ORM framework should be able to handle. I am also somewhat concerned that adding the two @Cascade
annotations may interfere with how Spring Data (JPA/REST) works though I have not run into any problems during testing - yet.
So my questions are:
- Is there a better way to save an entity including all its related entities in a single save when IDs are set using a custom generator?
- Is it reasonable to expect that the annotations do not cause problems with the Spring Data implementation?
PS: I know I could get the EntityManager autowired and save using that but I would lose (or maintain consistent duplicate implementations of) the per-method Spring Security checks attached to the various repositories using @PreAuthorize
and similar annotations.