Hibernate JPA ManyToOne composite key - java

I'm trying to setup my entity to allow to pks. My database consist of two fields,
dealer_detail_id pk
user_detail_id pk
Both join on id in corresponding tables.
I've tried this thus far without success.
#Embeddable
public class DealerUserPk implements Serializable {
private Integer dealerDetail;
private Integer userDetail;
DealerUser
#Embeddable
#Table(name = "dealer_user", schema = "account")
public class DealerUser implements Serializable {
#EmbeddedId
private DealerUserPk id;
#Id
#ManyToOne
#JoinColumn(name = "dealer_detail_id", referencedColumnName = "id")
private DealerDetail dealerDetail;
#Id
#ManyToOne
#JoinColumn(name = "user_detail_id", referencedColumnName = "id")
private UserDetail userDetail;
DealerDetail
#Entity
#Table(name = "dealer_detail", schema = "account")
public class DealerDetail implements Serializable {
#Id
private Integer id;
UserDetail
#Entity
#Table(name = "user_detail", schema = "account")
public class UserDetail implements Serializable {
#Id
private Integer id;
Can anybody spot what I'm doing wrong?

This is correct:
#Embeddable
public class DealerUserPk implements Serializable {
private Integer dealerDetail;
private Integer userDetail;
But your DealerUser is annotated with embeddable it should be #Entity
as you are using #Table annotation.
Need to add MapsId as it follows
#Entity
#Table(name = "dealer_user", schema = "account")
public class DealerUser implements Serializable {
#EmbeddedId
private DealerUserPk id;
#MapsId("dealerDetail")
#ManyToOne
#JoinColumn(name = "dealer_detail_id", referencedColumnName = "id")
private DealerDetail dealerDetail;
#Id
#MapsId("userDetail")
#JoinColumn(name = "user_detail_id", referencedColumnName = "id")
private UserDetail userDetail;
Try with that.

Try this
#Embeddable
public class DealerUserPk implements Serializable {
#ManyToOne
private DealerDetail dealerDetail;
#ManyToOne
private UserDetail userDetail;
public void setDealerDetail(DealerDetail dealerDetail) {
this.dealerDetail=dealerDetail;
}
public DealerDetail getDealerDetail(){
return this.dealerDetail;
}
public void setUserDetail(UserDetail userDetail) {
this.userDetail=userDetail;
}
public UserDetail getUserDetail() {
return this.userDetail;
}
}
and
#Entity
#Table(name = "dealer_user")
public class ProductItem {
#Id
private DealerUserPk id= new DealerUserPk();
// --- For bidirectional association---
#SuppressWarnings("unused")
#Column(name="dealer_detail_id", nullable=false, updatable=false, insertable=false)
private Integer dealerDetail;
#SuppressWarnings("unused")
#Column(name="user_details_id", nullable=false, updatable=false, insertable=false)
private Integer userDetail;
// ---
public void setDealerDetail(DealerDetail dealerDetail) {
id.setDealerDetail(dealerDetail);
}
public DealerDetail getDealerDetail(){
return id.getDealerDetail();
}
public void setUserDetail(UserDetail userDetail) {
id.setUserDetail(userDetail);
}
public UserDetail getUserDetail() {
return id.getUserDetail();
}
}

Related

Quarkus panache unidirectional OneToMany relationship

I want to implement a simple uni-directional one-to-many association. I have tried the below setup. But when I fetch the Tenant entity, I always see null for the subscriptions field.
#Getter
#Setter
#Entity
#ToString
public class Tenant {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String tenantKey;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name="tenantKey")
private Set<Subscription> subscriptions;
public Set<Subscription> getSubscriptions() {
return subscriptions;
}
public void setSubscriptions(Set<Subscription> subscriptions) {
this.subscriptions = subscriptions;
}
}
and below is the Subscription entity
#Entity
#Getter
#Setter
#ToString
public class Subscription {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String tenantKey;
private String serviceName;
}
Below is my repository class which I fetch the Tenant object
#ApplicationScoped
public class TenantRepository implements PanacheRepository<Tenant> {
public Uni<Tenant> findByTenantKey(String tenantKey) {
return find("tenantKey= ?1", tenantKey).firstResult();
}
}

JPA populate a composite key id part from parent entity

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!
Remove the #Column(name = "person_id", insertable = false, updatable = false) annotation from the InsurancePK.personId.
Add the following annotation:
#JoinColumn(name = "name = "person_id"")
to the Insurance.person.
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;
}

Making primary key same as foreign key in Hibernate entity

I am new to Hibernate. I am working on two entities as follows:
Entity 1 is as follows:
#Entity
#Table(name = "vm_user")
public class VmUser implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "created_by")
private String createdBy;
#Column(name = "last_modified_by")
private String lastModifiedBy;
#Column(name = "created_date")
private Instant createdDate;
#Column(name = "last_modified_date")
private Instant lastModifiedDate;
#OneToOne
#JoinColumn(unique = true)
private User user; <--- HOW WILL I DENOTE THIS PRIMARY KEY OF VMUSER ENTITY ?
In the associated table in mysql i.e. vm_user, user_id is both primary key as well as foreign key which refers to id of user table associated with User entity.
Entity 2 is as follows:
#Entity
#Table(name = "my_entity")
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "created_by")
private String createdBy;
#Column(name = "last_modified_by")
private String lastModifiedBy;
#Column(name = "created_date")
private Instant createdDate;
#Column(name = "last_modified_date")
private Instant lastModifiedDate;
#ManyToOne
private A a;
#OneToOne
#JoinColumn(unique = true)
private B b;
In the associated table in mysql i.e. my_entity, primary key is a combination of id of a and id of b. I am not getting how to denote this in Hibernate entity MyEntity.
Regarding the same, I have gone through a few posts: Hibernate foreign key as part of primary key and JPA & Hibernate - Composite primary key with foreign key, but no getting idea how to do these two ?
The solution is #MapsId
For example
#Entity
#Table(name = "vm_user")
public class VmUser implements Serializable {
#Id
#Column(name = "user_id")
private Integer id;
#MapsId
#OneToOne
private User user;
You can also remove the #JoinColumn(unique = true) because #Id makes it unique already.
public class MyEntityPk implements Serializable {
private Integer aId;
private Integer bId;
// IMPORTANT: Override equals() and hashCode()
}
#IdClass(MyEntityPk.class)
#Entity
#Table(name = "my_entity")
public class MyEntity implements Serializable {
#Id
private Integer aId;
#Id
private Integer bId;
#MapsId("aId")
#ManyToOne
private A a;
#MapsId("bId")
#OneToOne
private B b;
Please find more information in the Hibernate documentation https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-derived
You need to use #EmbeddedId and #MapsId ,
#Entity
#Table(name = "vm_user")
public class VmUser implements Serializable {
#Id
#Column(name = "user_id")
private Integer id;
#MapsId("user_id")
#OneToOne
private User user;
}
You can do the same thing for MyEntity as below,
#Embeddable
class BKey {
private int aId;
private int bId;
}
#Entity
#Table(name = "my_entity")
public class MyEntity implements Serializable {
#EmbeddedId
private BKey primaryKey;
#MapsId("aId")
#ManyToOne
private A a;
#MapsId("bId")
#OneToOne
#JoinColumn(unique = true)
private B b;
}
VM Users class
public class VmUser implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#OneToOne
#JoinColumn(name="ID")
private Users user;
Users class
public class Users implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#OneToOne(mappedBy="user")
private VmUser vmUser;
A class
#Entity
public class A implements Serializable {
#Id
private long id;
#OneToMany(mappedBy="a")
private List<MyEntity> myEntitys;
B Class
#Entity
public class B implements Serializable {
#Id
private long id;
#OneToMany(mappedBy="b")
private List<MyEntity> myEntitys;
MyEntity class
#Entity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private MyEntityPK id;
#ManyToOne
#JoinColumn(name="ID1")
private A a;
#ManyToOne
#JoinColumn(name="ID2")
private B b;
MyEntityPK class
#Embeddable
public class MyEntityPK implements Serializable {
#Column(insertable=false, updatable=false)
private long id1;
#Column(insertable=false, updatable=false)
private long id2;

Hibernate - the custom query did not find the entity by the child parameter for ManyToOne unidirectional relation

I have a problem with retrieving an entity using the child's entity as a search parameter. Entities are related to many to one relationship as unidirectional and each object is fetched as FetchType.LAZY.
When I looking for an entity by a child entity, the result is null. But when I set to fetch as Eager it is correct.
My Entities:
#NoArgsConstructor
#Getter
#Entity
#Table(name = "partner")
public class PartnerEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String login;
public PartnerEntity(String login) {
this.login = login;
}
}
#NoArgsConstructor
#Getter
#Entity
#Table(name = "point")
public class PointEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "partner_Id")
private PartnerEntity partnerEntity;
public PointEntity(PartnerEntity partnerEntity) {
this.partnerEntity = partnerEntity;
}
}
#NoArgsConstructor
#Getter
#Entity
#Table(name = "orer")
public class OrdEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PAYMENT_POINT_ID")
private PointEntity pointEntity;
public OrdEntity(PointEntity pointEntity) {
this.pointEntity = pointEntity;
}
}
#NoArgsConstructor
#ToString
#Getter
#Entity
#Table(name = "BL")
public class BLEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PARTNER_LOGIN", referencedColumnName = "login")
private PartnerEntity partnerEntity;
private String number;
public BLEntity(PartnerEntity partnerEntity, String number) {
this.partnerEntity = partnerEntity;
this.number = number;
}
}
And I looking for BLEntity using OrdEntity child:
final OrdEntity byId = ordRepo.findById(id);
final PartnerEntity partnerEntity = order.getPointEntity().getPartnerEntity();
final BLEntity blEntityResult= blRepo.findOneByNumberAndPartner(number, partnerEntity);
The object partnerEntity is not null, it is correct object.
I got blEntityResult as null but if I change in PointEntity fetch to FetchType.EAGER, blEntityResult is not null(correct).
My custom query in repository below:
public interface BLRepo extends JpaRepository<BLEntity, Long> {
#Query("select b from BLEntity b where b.number = :number and b.partnerEntity= :partner")
BLEntity findOneByNumberAndPartner(#Param("number") String number, #Param("partner") PartnerEntity partner);
}
why does happens, if the partner object being downloaded is not null and is correct?
I think you should add the mapping in both sides,
because of default fetch type for #AllToMany=Lazy and #ManyToAll = Eager.
just add below code inside PartnerEntity.
#OneToMany(mappedBy="partnerEntity" , fetch = FetchType.Eager )
List<BLEntity> blEntity = new ArrayList<>();
I change FetchType into Eager in PointEntity:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "partner_Id")
private PartnerEntity partnerEntity;
And everything is ok, but I don't understand why it does not work with PaymentType.Lazy. When I am looking for:
final PartnerEntity partnerEntity = order.getPointEntity().getPartnerEntity();
I get correct entity "PartnerEntity" which has proper login's field (login'field has value "test").
When I turned logged level to 'TRACE' I saw, Hibernate not binding correct login's parameter, it set null instead "test") why? :)

HIbernate #OneToOne mapping

I have a PatientVisit.java that has a one to one mapping with the PatientVisitObject.java:
#Entity
#Table(name = "P_Visit")
public class PatientVisit extends Bean {
#Id
#Column(name = "PATIENT_VISIT_SEQ")
private Long patientVisitSeq;
#Column(name = "PATIENT_FIRST_NM")
private String firstName;
#Column(name = "PATIENT_LAST_NM")
private String lastName;
#Column(name = "PATIENT_MIDDLE_NM")
private String middleName;
#OneToOne
private PatientVisitObject pvo;
}
The PatientVisitObject.java has a composite key. I need to map key.patientVisitSeq to my patientVisitSeq in the PatientVisit.java.
#Entity
#Table(name = "Patient_V_O")
public class PatientVisitObject extends Bean {
#Id
private PatientVisitObjectKey key;
#Column(name = "FIELD")
private String field;
}
Here is the key:
#Embeddable
public class PatientVisitObjectKey implements Serializable {
#Column(name = "PATIENT_VISIT_SEQ")
private Long patientVisitSeq;
#Column(name = "PATIENT_VISIT_OBJECT_SEQ")
private Long patientVisitObjectSeq;
}
I have tried using the #JoinTable annotation and cannot get it right. Could someone please give me some direction. Thanks.
You need to use bidirectional mapping with PatientVisit being the inverse side of relationship:
public class PatientVisit extends Bean {
...
#OneToOne(mappedBy = "pv")
private PatientVisitObject pvo;
...
}
public class PatientVisitObject extends Bean {
#EmbeddedId
private PatientVisitObjectKey key;
#OneToOne
#MapsId("patientVisitSeq")
private PatientVisit pv;
...
}
See also:
#MapsId

Categories

Resources