1

Let's say I have those two entities, Person & Insurance. One Person can have multiple insurances, and the insurance uniqueness is maintained by a composite key combination of (insurance type, policy number, and person id). The below code represent the the scenario...

parent class

@Entity
@Setter
@Getter
@RequiredArgsConstructor
public class Person implements Serializable {

  @Id
  @GeneratedValue(strategy = "GenerationType.IDENTITY")
  @Column(name "person_id")
  private Long personId;

  @Column(name = "fst_nm")
  private String fstName;

  @Column(name = "lst_nm")
  private String lstNm;
  
  // ..Other columns & relationships
  
  @OneToMany(mappedBy = "person")
  private List<Insurance> insurances;

  public void addInsurance(Insurance toAdd) {
    getInsurances().add(toAdd);
    toAdd.setPerson(this);
  }
}

child class

@Entity
@Setter
@Getter
@RequiredArgsConstructor
public class Insurance implements Serializable {

  @EmbeddedId
  private insurancePK id;

  //other data

  @ManyToOne
  @MapsId("personId")
  private Person person;
}

composite PK class

@Setter
@Getter
@Embeddable
public class InsurancePK implements Serializable {

  @Column(name = "person_id", insertable = false, updatable = false)
  private Long personId;

  @Column(name = "insurance_type")
  private String insuranceType;

  @Column(name = "pol_num")
  private String polNum;
}

now, my data mapper looks something like that...

  Person newPerson = new Person();
  newPerson.setInsurances(new ArrayList<>());

  // fill out Person Model data

  // incoming insurance data
  while (incomingData.hasNext()) {
    Insurance insuranceData = new Insurance();
    InsurancePK pk = new InsurancePK();

    // set other insurance data

    pk.setInsuranceType("Dental");
    pk.setPolNum("123Abc00");

    insuranceData.setId(pk);
    person.addInsurance(insuranceData);
  }

Problem is my person_id inside the composite key is always getting a null value, not sure why (shouldn't the @MapsId takes care of that value)? I need to fetch that value dynamically, most of the JPA composite key solutions only are setting all the value manually, but that's not my scenario.

return object from saveAndflush()

{
  person: {
    person_id: 55,
    fst_nm: blah,
    lst_nm: blah,
    insurances: [
      {
        insurance_pk: {
          person_id: null,
          insurance_type: "Dental",
          pol_num: "123Abc00"
        }
       //other insurance data
      }
    ]
  }
}

any suggestions on what am I missing? Thank you in advance!

ad3luc
  • 192
  • 1
  • 7
  • 22
Saher
  • 105
  • 1
  • 13
  • Does this answer your question? [JPA how to make composite Foreign Key part of composite Primary Key](https://stackoverflow.com/questions/31385658/jpa-how-to-make-composite-foreign-key-part-of-composite-primary-key) – Justin Mathew Apr 15 '21 at 18:39
  • 1
    not really, because that implies I still need to set the MeetingId (in my case InsuranceId) manually... and I don't have all the values to that inside the mapper, since the personId is not decided yet & will be null. – Saher Apr 15 '21 at 19:09

2 Answers2

0
  1. Remove the @Column(name = "person_id", insertable = false, updatable = false) annotation from the InsurancePK.personId.

  2. Add the following annotation:

@JoinColumn(name = "name = "person_id"")

to the Insurance.person.

SternK
  • 11,649
  • 22
  • 32
  • 46
  • removing the annotation and adding `@JoinColumn(name = "name = \"person_id\"");` didn't work either! – Saher Apr 15 '21 at 20:08
  • You did not show how you save your entities. If you use for example `entityManager.persist(newPerson)` then you should also add a proper cascading `@OneToMany(mappedBy = "person", cascade = CascadeType.PERSIST)` – SternK Apr 15 '21 at 20:25
  • That was a great pointer about adding cascade, it put me in the right track to fix my issue. Thank you! – Saher Apr 16 '21 at 16:42
0

As mentioned in the comments, adding a cascade to my entity column started me on the right track. just in case, that's the model that worked for me after couple of tries

Parent class

@Entity
@Setter
@Getter
@RequiredArgsConstructor
public class Person implements Serializable {

  @Id
  @GeneratedValue(strategy = "GenerationType.IDENTITY")
  @Column(name "person_id")
  private Long personId;

  @Column(name = "fst_nm")
  private String fstName;

  @Column(name = "lst_nm")
  private String lstNm;
  
  // ..Other columns & relationships
  
  // cascade added  <-- thanks to SternK
  @OneToMany(mappedBy = "person", casecade = CascadeType.ALL, orphanRemoval = true)
  private List<Insurance> insurances;

  public void addInsurance(Insurance toAdd) {
    getInsurances().add(toAdd);
    toAdd.setPerson(this);
  }
}

Child class

@Entity
@Setter
@Getter
@RequiredArgsConstructor
public class Insurance implements Serializable {

  @EmbeddedId
  private insurancePK id;

  //other data

  @ManyToOne
  @MapsId("personId")
  // annotation added here instead of PK class  <-- fix
  @JoinColumn(name="person_id", nullable = false, insertable = false, updatable = false)
  private Person person;
}

PK class

@Setter
@Getter
@Embeddable
public class InsurancePK implements Serializable {
  //annotation removed  <-- fix thanks to SternK
  private Long personId;

  @Column(name = "insurance_type")
  private String insuranceType;

  @Column(name = "pol_num")
  private String polNum;
}
ad3luc
  • 192
  • 1
  • 7
  • 22
Saher
  • 105
  • 1
  • 13