0

So I have the following entity:

@Entity
@Table(name = "appointment")
public class Appointment {
@EmbeddedId 
private AppointmentId id = new AppointmentId();

@ManyToOne(fetch = FetchType.LAZY)
@MapsId("customerId")
@JoinColumn(name = "customerId") //Remember to use joincolumns to rename the generated column is spring creates it
private Customer customer;

@ManyToOne(fetch = FetchType.LAZY)
@MapsId("barberId")
@JoinColumn(name = "barberId") //Remember to use joincolumns to rename the generated column is spring creates it
private Barber barber;

@Column(name = "notes")
private String notes;

public Appointment(Customer customer, Barber barber, String notes) {
    this.customer = customer;
    this.notes = notes;
    this.barber = barber;
}

public Appointment() {
}

@JsonBackReference
public Customer getCustomer() {
    return customer;
}

public void setCustomer(Customer customer) {
    this.customer = customer;
}

public String getNotes() {
    return notes;
}

public void setNotes(String notes) {
    this.notes = notes;
}

@Override
public String toString() {
    return "Appointment{" +
            ", notes='" + notes + '\'' +
            '}';
}
}

And this is the AppointmentId:

@SuppressWarnings("serial")
@Embeddable
public class AppointmentId implements Serializable {
    private Integer barberId;
    private Integer customerId;
}

Now I was following a tutorial in which I managed to accomplish what I wanted to do. The key was to add the @EmbeddedId annotation and create the AppointmentId class.

I currently have 3 records in my 'Appointment' table in the DB. And each record has a primary key and the value is 1,2,3 resepctively.

I'm trying to fetch the 2nd record so I'm using the .findById(2) method from my interface which extends JpaRespository<Appointment, Integer> but I get the following error. I'm not sure why:


org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.gogobarber.barber.entities.Appointment. Expected: class com.gogobarber.barber.entities.AppointmentId, got class java.lang.Integer

I mean the error is self explantory.. it's asking for the ID in the form of AppointmentId but how can I create such an object without knowing the customer or the barber id?

EDIT = This is my table schema for Appointments:

Table: appointment
Columns:
idappointment int AI PK 
notes varchar(255) 
barberId int 
customerId int

EDIT =

Controller:

@DeleteMapping("/appointment/{appointmentId}")
public void deleteAppointment(@PathVariable String appointmentId)
{
    appointmentService.deleteAppointment(appointmentId);
}

Service:

@Transactional
public void deleteAppointment(String appointmentId) {
    appointmentRepo.deleteById(Integer.valueOf(appointmentId));
}
tcho1506996
  • 105
  • 6
  • 1
    If I understand you correctly, then the database schema does not have a sequential primary key for the table `Apppointment`. If it has, then it is not reflected in the `@Entity`. Can you [edit] the post and add your database schema? – Turing85 Dec 30 '21 at 14:59
  • You have two option either `IdClass` or `EmbeddedId` because you have `Composite Primary Keys`. and you have to display your `controller` also – Faheem azaz Bhanej Dec 30 '21 at 15:22
  • @Turing85 I have updated the post to refelct the schema of the table – tcho1506996 Dec 30 '21 at 15:25
  • Where the `Controller` and `service` – Faheem azaz Bhanej Dec 30 '21 at 15:26
  • The setup of the entity class is wrong. The actual primary key (id) is the `idappointment`, i.e. `class Appointment` should have a field `Integer idAppointment` annotated with `@Id @GeneratedValue`. The `@EmbeddedId` is superfluous. – Turing85 Dec 30 '21 at 15:29
  • @FahimazazBhanej Yes you are right. I had to change that because of this issue I was facing: https://stackoverflow.com/questions/70532165/how-to-model-two-onetomany-relationship -- I then followed this answer: https://stackoverflow.com/questions/53599853/spring-data-jpa-multi-bidirectional-manytoone-propagation-data which made me get to the above state using embeddedID – tcho1506996 Dec 30 '21 at 15:30

1 Answers1

0

I had similar problem recently. At first to get the composite primary key I used the @EmbeddedId but later I found out that adding additional abstraction level added more complexity and for example using of HashMap or HashSet needs additional logic to represent the keys. So my recommendation is to use the internal generated database ID as key and for unique columns just add a unique constrain:

@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "barberId", "customerId" }) })
  • I see. but in this case I don't need barber and customer id's to be unique. E.g. the same customer could book an appointment with the same barber multiple times hence each row should have a unique ID (which i have in my case but my spring app is not able to get it) – tcho1506996 Dec 30 '21 at 15:34
  • I thought you would like that the combination of these foreign keys is unique? If you use constaraint you will get just additional primary key for access and the combination of both foreign keys is unique by constraint. – The 5th column mouse Dec 30 '21 at 15:39
  • Actually, you can continue to use your class AppointmentId as a represantation in the service layer but in the data layer you don't really need it. – The 5th column mouse Dec 30 '21 at 15:43