Issue
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?
Solution
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.
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
Answered By - Arkadiusz