1

Floor.java

@Entity
@Getter
@Setter
@AllArgsConstructor
@Table(name = "floors")
@Builder
public class Floor {

    @Id
    @Column(name = "floor_id", nullable = false)
    private String floorId;
    @Column(name = "floor_name", nullable = false)
    private String floorName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "building_id", nullable = true)
    @JsonBackReference
    private Building building;

    @Column(name = "floor_order", nullable = false)
    private int floorOrder;
    @Column(name = "floor_image_url", nullable = true)
    private int floorImageUrl;

    @OneToMany(mappedBy = "floor", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST,
        CascadeType.MERGE }, orphanRemoval = true)
    @JsonManagedReference
    private List<Seat> seats;
}

Seat.java

@Entity
@Getter
@Setter
@AllArgsConstructor
@Builder
@Table(name = "seats")
public class Seat {

    @Id
    @Column(name = "seat_id", nullable = false)
    private String seatId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "floor_id", nullable = false) // owner of the relationship
    @JsonBackReference
    private Floor floor;
    @Column(name = "x", nullable = false)
    private double x;
    @Column(name = "y", nullable = false)
    private double y;
    @Column(name = "is_group", nullable = false)
    private Boolean isGroup;

    @Column(name = "group_id", nullable = true)
    private String groupId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "employee_id") // owner of the relationship
    @JsonBackReference
    private Employee employee;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "figure_id", nullable = false)
    private Figure figure;
}

FloorController.java(Code being modified)

package com.hancom.hanzari.controllers;

import java.util.ArrayList;
import java.util.List;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.hancom.hanzari.dto.FloorDto;
import com.hancom.hanzari.exception.ResourceNotFoundException;
import com.hancom.hanzari.model.Building;
import com.hancom.hanzari.model.Floor;
import com.hancom.hanzari.service.BuildingService;
import com.hancom.hanzari.service.FloorService;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("api/buildings/{building_id}/floors")
public class FloorController {

    @Autowired
    private FloorService floorService;
    @Autowired
    private BuildingService buildingService;

    @Transactional
    @GetMapping(produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<List<FloorDto>> getAllFloorsInBuilding(@PathVariable("building_id") String buildingId)
            throws Exception {
        Building building = buildingService.findById(buildingId);
        if (building == null) {
            throw new ResourceNotFoundException("Building", "building_id", buildingId);
        }
        List<Floor> floor = floorService.findByBuilding(building);
        List<FloorDto> result = new ArrayList<FloorDto>();
        floor.forEach(e -> result.add(e.toDto()));
        return new ResponseEntity<List<FloorDto>>(result, HttpStatus.OK);
    }

    @Transactional
    @GetMapping(value = "/{floor_id}", produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<FloorDto> getFloor(@PathVariable("building_id") String buildingId,
            @PathVariable("floor_id") String floorId) throws Exception {
        Building building = buildingService.findById(buildingId);
        if (building == null) {
            throw new ResourceNotFoundException("Building", "building_id", buildingId);
        }
        return new ResponseEntity<FloorDto>(floorService.findById(floorId).toDto(), HttpStatus.OK);
    }

    @Transactional
    @PostMapping
    public ResponseEntity<Floor> save(@PathVariable("building_id") String buildingId, @RequestBody FloorDto floorDto)
            throws Exception {
        /*
         * for (Field field : floorDto.getClass().getDeclaredFields()) {
         * field.setAccessible(true); Object value = field.get(floorDto);
         * System.out.println(field.getName() + " : " + value + " // type : " +
         * value.getClass()); }
         */

        Building building = buildingService.findById(buildingId);
        if (building == null) {
            throw new ResourceNotFoundException("Building", "building_id", buildingId);
        }
        /*Floor newFloor = Floor.builder().floorId(floorDto.getFloor_id()).floorName(floorDto.getFloor_name())
                .building(building).floorOrder(floorDto.getFloor_order()).build();*/
        
        
        
        Floor newFloor = new Floor();
        newFloor.setFloorId(floorDto.getFloor_id());
        newFloor.setFloorName(floorDto.getFloor_name());
        newFloor.setFloorOrder(floorDto.getFloor_order());
        newFloor.setBuilding(building);
        //newFloor.setSeats(new ArrayList<Seat>());
        
        if(newFloor.getSeats() == null) {
            System.out.println("#####\n#####\nseats null#####\n#####\n");
        }
        else {
            System.out.println("#####\n#####\nseats not null#####\n#####\n");
        }
        
        floorService.save(newFloor);
        
        return new ResponseEntity<Floor>(newFloor, HttpStatus.OK);
    }

    @DeleteMapping(value = "/{floor_id}", produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<Void> deleteFloorById(@PathVariable("floor_id") String floor_id) {
        System.out.println("==================================================================");
        System.out.println("seatId: " + floor_id);
        System.out.println("==================================================================");

        floorService.deleteById(floor_id);
        return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
    }
}

Floor and Seat have a bidirectional relationship owned by Floor.

The problem occurs when calling FloorController.save() for the floor. FloorController.save()

When I first save() a Floor object, it works correctly. SUCCESS

But I want to be able to edit the already saved Floor, so in order to modify the information of an existing object, it fails if the value to be modified (modify "floor_name") is delivered in the form of Dto including the floor_id of the existing object. FAIL

The error that occurs is:

2020-10-27 14:32:59.436 ERROR 10508 --- [nio-8081-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemExce
ption: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.hancom.hanzari.model.Floor.seats; nested exception is javax.persistence.PersistenceException: org.hibernate.HibernateException: A col
lection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.hancom.hanzari.model.Floor.seats] with root cause

org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.hancom.hanzari.model.Floor.seats
   at org.hibernate.engine.internal.Collections.processDereferencedCollection(Collections.java:100) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.engine.internal.Collections.processUnreachableCollection(Collections.java:51) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.event.internal.AbstractFlushingEventListener.lambda$flushCollections$1(AbstractFlushingEventListener.java:255) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.engine.internal.StatefulPersistenceContext.forEachCollectionEntry(StatefulPersistenceContext.java:1136) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:252) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:93) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1363) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:454) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3213) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2381) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
   at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:534) ~[spring-orm-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743) ~[spring-tx-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711) ~[spring-tx-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:633) ~[spring-tx-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:386) ~[spring-tx-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178) ~[spring-data-jpa-2.3.3.RELEASE.jar:2.3.3.RELEASE]
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
   at com.sun.proxy.$Proxy117.save(Unknown Source) ~[na:na]

As a result of searching for the related error, I found that it was an error that was caused by Hibernate not managing the List<Seat> seats referenced in the Floor.

ahndding
  • 11
  • 2

0 Answers0