I spent many times to solve this problem - I know, this is very common problem but I can't find any solution!
I try to save my object (in one shot) that consists of some nested objects/collections. I want to fill window object with data from windowDto and then save window object in db together with nested objects
I get the following error:
object references an unsaved transient instance - save the transient instance before flushing : pl.entity.Window.path-> window.domain.model.entity.Path
I want to save object window:
@EqualsAndHashCode(callSuper = false, of = "id")
@Builder
@Entity
@Table(name = "window")
@Getter
@Setter
public class Window {
       @Column(nullable = false, updatable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "path_id", foreignKey = @ForeignKey(name = "FK_path_w"))
    private Path path;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "store_id", foreignKey = @ForeignKey(name = "FK_store_w"))
    @NotNull
    private Store store;
}
Then my first nested objects:
@Entity
@Getter
@Setter
@EqualsAndHashCode(callSuper = false, of = "uuid")
@NoArgsConstructor
public class Path {
    @Column(nullable = false, updatable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @OrderBy(value = "point_order asc")
    @OneToMany(mappedBy = "path", cascade = CascadeType.ALL, orphanRemoval = true)
    Set<Point> points;
    public void replacePoints(Set<Point> points) {
        if (!CollectionUtils.isEmpty(this.getPoints())) {
            this.getPoints().clear();
        }
        if (this.getPoints() != null) {
            this.getPoints().addAll(points);
        } else {
            this.setPoints(points);
        }
    }
    public void removePoint(Point point) {
        point.setPath(null);
        this.getPoints().remove(point);
    }
}
Path has points:
@Entity
@Getter
@Setter
@Table(name = "point")
public class Point {
    @Column(nullable = false, updatable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @OrderBy(value = "operation_order asc")
    @OneToMany(mappedBy = "point", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private Set<PointOperation> operations;
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "path_id", foreignKey = @ForeignKey(name = "FK_point_path"), nullable = false)
    private Path path;
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.DETACH}, fetch = FetchType.LAZY)
    @JoinColumn(name = "path_address_id", foreignKey = @ForeignKey(name = "FK_point_path_address"), nullable = false)
    private PathAddress pathAddress;
    public void removePointOperation(PointOperation spotOperation) {
        pointOperation.setPoint(null);
        this.getOperations().remove(pointOperation);
    }
}
And my second nested objects/collection:
Entity
@Getter
@Setter
@Table(name = "point_operation")
public class PointOperation {
    @Column(nullable = false, updatable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "point_id", foreignKey = @ForeignKey(name = "FK_point_point_operation"), nullable = false)
    private Point point;
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "window_id", foreignKey = @ForeignKey(name = "FK_point_w"))
    private Window window;
}
I try to save my object window in my service, in transaction:
    @Transactional
    public myService() {
    //window object is not persisted - its just a POJO mapped from windowDto (with id = null)
    
    pointsModifier.modifyPoints(window, windowDto);
    Window savedWindow= windowRepository.save(window);
    }
and the after transaction I invoke in my controller:
    return mapper.map(getMyWindow(), ClassOnlyWithWindowId.class);
In pointsModifier method I just modify points from window:
@RequiredArgsConstructor
@Service
public class PointsModifier {
    private final StoreRepository warehouseRepository;
    private final Mapper mapper;
    public void modifyPoints(Window window, WindowWriteDto windowWriteDto) {
        warehouseRepository.findById(windowWriteDto.getStore().getId())
                .ifPresent(windowStore -> {
                    for (Point point : window.getPath().getPoints()) {
                        point.setPath(window.getPath());
                        setPointPathAddress(point, windowWriteDto, windowStore, window);
                    }
                });
    }
    private void setPointPathAddress(Point point, WindowWriteDto windowDto, Store windowStore, Window window) {
        windowDto.getPath().getPoints().stream()
                .filter(s -> s.getOrder().equals(point.getOrder()))
                .findFirst()
                .ifPresent(pointDto -> {
                    if (pointDto.getStoreId() != null && pointDto.getStoreId().equals(windowStore.getId())) {
                        point.setPathAddress(mapper.map(windowStore, PathAddress.class));
                    } else {
                        point.setPathAddress(mapper.map(pointDto.getPathAddress(), PathAddress.class));
                    }
                    setOperations(pointDto, point, window);
                });
    }
    private void setOperations(PointWriteDto pointDto, Point point, Window window) {
        for (PointOperation pointOperation : point.getOperations()) {
            pointOperation.setPoint(point);
            pointDto.getOperations().stream()
                    .filter(op -> op.getOrder().equals(pointOperation.getOrder()))
                    .findFirst()
                    .ifPresent(pointOperationDto -> {
                        if (pointOperationDto.isInside()) {
                            pointOperation.setWindow(window);
                        }
                    });
        }
    }
What is wrong with my code? Why I can't save my object with nested objects in one shot?
