Home > Blockchain >  How to properly create a new child in oneToMany relationship to avoid managed flush and detached ent
How to properly create a new child in oneToMany relationship to avoid managed flush and detached ent

Time:10-15

The booking system involves entities: User, Reservation, Course.
Problem: ReservationService doesn't add the reservation to the database nor to the user. Auto-generated long id of Reservation reservation = new Reservation(); is 0 [I tried Sequence generation type, didn't work]. Then, reservationService.addReservation(reservation); causes an error: detached entity passed to persist. Relationships:

User -- oneToMany --> Reservation -- oneToOne --> Course

ReservationController:

@Controller
public class ReservationController {

    private final AppUserService appUserService;
    private final ReservationService reservationService;
    private final CourseService courseService;

    public ReservationController(AppUserService appUserService, ReservationService reservationService, CourseService courseService) {
        this.appUserService = appUserService;
        this.reservationService = reservationService;
        this.courseService = courseService;
    }

    @RequestMapping(value = "bookCourse/{courseId}")
    public String bookCourse(@PathVariable("courseId") long id, Principal principal) {

        AppUser user = appUserService.getAppUser(principal.getName());
        Course course = courseService.getCourse(id);

        Reservation reservation = new Reservation();

        reservation.setAppUser(user);
        reservation.setCourse(course);

        reservationService.addReservation(reservation);

        user.getReservations().add(reservation); //this line causes the error:       
        //org.hibernate.PersistentObjectException: detached entity passed to persist: application.domain.Course

        appUserService.editAppUser(user);

        return "redirect:/reservations.html";
    }

Reservation Service Implementation:

@Service("reservationService")
@Transactional
public class ReservationServiceImpl implements ReservationService {

    private final ReservationRepository reservationRepository;

    @Autowired
    public ReservationServiceImpl(ReservationRepository reservationRepository) {
        this.reservationRepository = reservationRepository;
    }

    @Transactional
    public void addReservation(Reservation reservation) {
        reservationRepository.save(reservation);
    };

User.java:

@Entity
@Table(name="appuser")
public class AppUser {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    long id;

    @OneToMany(mappedBy="appUser", cascade = CascadeType.ALL)
    private Set<Reservation> reservations;

    //getters and setters
}

Reservation.java:

@Entity
@Table(name="reservation")
public class Reservation {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @OneToOne(cascade = CascadeType.ALL)
    @JsonManagedReference
    private Course course;

    @ManyToOne(fetch = FetchType.EAGER)//(mappedBy="reservation")
    private AppUser appUser;

    //getters and setters

Course.java:

@Entity
@Table(name="course")
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotEmpty
    private String name;

    @NotEmpty
    private String price;

    @JsonBackReference
    @OneToOne(mappedBy="course")
    private Reservation reservation;
   
    //getters and setters

In the database, an appuser_reservation junction table has been created to link the ids of a user and a reservation.
In the database, reservation has appuser_id and course_id "automatically" created, and of bigint type.

The ReservationController method is referenced by clicking in course list html:

<a href="bookCourse/${course.id}">Book!</a> 

[course already is in the Database]

Framework is Spring, database is PostgreSQL.

If there are more information needed, please let me know!

Since I don't know if the issue is that new Reservation() creates a reservation with a null id, so then it can't be properly saved to DB by the service, or there is some other, more general issue, I don't know if the title of this question is appropriate.

I know the error in itself has been discussed, but I am unable to solve this issue for days now and I'll be immensely grateful for all insight. Perhaps I make an error in understanding relationships or how new Entity() works.

What is going wrong in bookCourse{id} with creating a new Reservation(); and writing it to the database?

CodePudding user response:

OK, we met in person and solved the problem.

Relationship with JPA and Hibernate were wrong.
You need to change the relationship in Reservation to be:

@Entity
@Table(name="reservation")
public class Reservation { 
...
@ManyToOne
private Course course;
...
}

You have a live drawing here so you can remember what is what and what the relationship is. live drawing

auto-generated long id of Reservation reservation = new Reservation(); is 0

First you need to add created entity to database and fetch it to gets auto-generated id like this:

Reservation reservation = new Reservation();  
// fill the reservation

// I assume there is repository.save(reservation); 
Reservation reservationWithID = reservationService.add(reservation);

// assign reservationWithID to User Reservation List to create connection
  • Related