0

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?

Matley
  • 1,953
  • 4
  • 35
  • 73
  • Does this answer your question? [How to fix the Hibernate "object references an unsaved transient instance - save the transient instance before flushing" error](https://stackoverflow.com/questions/2302802/how-to-fix-the-hibernate-object-references-an-unsaved-transient-instance-save) – Jens Schauder Feb 11 '21 at 07:26
  • maybe but I can't apply this solution to my case:( I have cascade type ALL everywhere, on my every collection... – Matley Feb 11 '21 at 08:43
  • @JensSchauder do you see any error/missing cascade in my code? – Matley Feb 11 '21 at 10:14
  • Window and Point and PoinOperation that are completely NEW objects, not persisted before in database – Matley Feb 11 '21 at 11:27
  • You don't have a cascade on `Window.path` just where the error complains about. – Jens Schauder Feb 11 '21 at 11:42
  • The same error, nothing chanes – Matley Feb 11 '21 at 12:06
  • @JensSchauder After adding cascade type ALL to Window.path i get: org.hibernate.PersistentObjectException: detached entity passed to persist: pl.model.entity.Point – Matley Feb 11 '21 at 12:13
  • Currently I added cascade type MERGE to WIndow.Path and in my service method that saves WIndow object I have to save it twice! because after first save Window.Path.id = null but points inside Path have ids != null – Matley Feb 11 '21 at 12:27
  • @JensSchauder twice I mean windowRepository.save(window); Why??? – Matley Feb 11 '21 at 12:41
  • I have to save window twice, otherwise I get error object references an unsaved transient instance - save the transient instance before flushing – Matley Feb 11 '21 at 13:07
  • 1
    Looks like we solved your first question. Time to ask a new one. To be honest I lost track in the comments how your code currently looks like and what the current problem is. – Jens Schauder Feb 11 '21 at 16:33
  • You're right - I created next topic - I welcome you: https://stackoverflow.com/questions/66158260/spring-jpa-detached-entity-passed-to-persist-how-to-save-parent-and-child-in – Matley Feb 11 '21 at 16:38

0 Answers0