#OneToMany and composite primary keys? - java
I'm using Hibernate with annotations (in spring), and I have an object which has an ordered, many-to-one relationship which a child object which has a composite primary key, one component of which is a foreign key back to the id of the parent object.
The structure looks something like this:
+=============+ +================+
| ParentObj | | ObjectChild |
+-------------+ 1 0..* +----------------+
| id (pk) |-----------------| parentId |
| ... | | name |
+=============+ | pos |
| ... |
+================+
I've tried a variety of combinations of annotations, none of which seem to work. This is the closest I've been able to come up with:
#Entity
public class ParentObject {
#Column(nullable=false, updatable=false)
#Id #GeneratedValue(generator="...")
private String id;
#OneToMany(mappedBy="parent", fetch=FetchType.EAGER, cascade={CascadeType.ALL})
#IndexColumn(name = "pos", base=0)
private List<ObjectChild> attrs;
...
}
#Entity
public class ChildObject {
#Embeddable
public static class Pk implements Serializable {
#Column(nullable=false, updatable=false)
private String parentId;
#Column(nullable=false, updatable=false)
private String name;
#Column(nullable=false, updatable=false)
private int pos;
#Override
public String toString() {
return new Formatter().format("%s.%s[%d]", parentId, name, pos).toString();
}
...
}
#EmbeddedId
private Pk pk;
#ManyToOne
#JoinColumn(name="parentId")
private ParentObject parent;
...
}
I arrived at this after a long bout of experimentation in which most of my other attempts yielded entities which hibernate couldn't even load for various reasons.
UPDATE: Thanks all for the comments; I have made some progress. I've made a few tweaks and I think it's closer (I've updated the code above). Now, however, the issue is on insert. The parent object seems to save fine, but the child objects are not saving, and what I've been able to determine is that hibernate is not filling out the parentId part of the (composite) primary key of the child objects, so I'm getting a not-unique error:
org.hibernate.NonUniqueObjectException:
a different object with the same identifier value was already associated
with the session: [org.kpruden.ObjectChild#null.attr1[0]]
I'm populating the name and pos attributes in my own code, but of course I don't know the parent ID, because it hasn't been saved yet. Any ideas on how to convince hibernate to fill this out?
Thanks!
The Manning book Java Persistence with Hibernate has an example outlining how to do this in Section 7.2. Fortunately, even if you don't own the book, you can see a source code example of this by downloading the JPA version of the Caveat Emptor sample project (direct link here) and examining the classes Category and CategorizedItem in the auction.model package.
I'll also summarize the key annotations below. Do let me know if it's still a no-go.
ParentObject:
#Entity
public class ParentObject {
#Id #GeneratedValue
#Column(name = "parentId", nullable=false, updatable=false)
private Long id;
#OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
#IndexColumn(name = "pos", base=0)
private List<ChildObject> attrs;
public Long getId () { return id; }
public List<ChildObject> getAttrs () { return attrs; }
}
ChildObject:
#Entity
public class ChildObject {
#Embeddable
public static class Pk implements Serializable {
#Column(name = "parentId", nullable=false, updatable=false)
private Long objectId;
#Column(nullable=false, updatable=false)
private String name;
#Column(nullable=false, updatable=false)
private int pos;
...
}
#EmbeddedId
private Pk id;
#ManyToOne
#JoinColumn(name="parentId", insertable = false, updatable = false)
#org.hibernate.annotations.ForeignKey(name = "FK_CHILD_OBJECT_PARENTID")
private ParentObject parent;
public Pk getId () { return id; }
public ParentObject getParent () { return parent; }
}
You should incorporate the ParentObject reference just into ChildObject.Pk rather than map parent and parentId separately:
(getters, setters, Hibernate attributes not related to problem and member access keywords omitted)
class ChildObject {
#Embeddable
static class Pk {
#ManyToOne...
#JoinColumn(name="parentId")
ParentObject parent;
#Column...
String name...
...
}
#EmbeddedId
Pk id;
}
In ParentObject you then just put #OneToMany(mappedBy="id.parent") and it works.
Firstly, in the ParentObject, "fix" the mappedBy attribute that should be set to "parent". Also (but this is maybe a typo) add an #Id annotation:
#Entity
public class ParentObject {
#Id
#GeneratedValue
private String id;
#OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
#IndexColumn(name = "pos", base=0)
private List<ObjectChild> attrs;
// getters/setters
}
Then, in ObjectChild, add a name attribute to the objectId in the composite key:
#Entity
public class ObjectChild {
#Embeddable
public static class Pk implements Serializable {
#Column(name = "parentId", nullable = false, updatable = false)
private String objectId;
#Column(nullable = false, updatable = false)
private String name;
#Column(nullable = false, updatable = false)
private int pos;
}
#EmbeddedId
private Pk pk;
#ManyToOne
#JoinColumn(name = "parentId", insertable = false, updatable = false)
private ParentObject parent;
// getters/setters
}
AND also add insertable = false, updatable = false to the #JoinColumn because we are repeating the parentId column in the mapping of this entity.
With these changes, persisting and reading the entities is working fine for me (tested with Derby).
After much experimentation and frustration, I eventually determined that I cannot do exactly what I want.
Ultimately, I went ahead and gave the child object its own synthetic key and let Hibernate manage it. It's a not ideal, since the key is almost as big as the rest of the data, but it works.
Found this question searching for the answer to it's problem, but it's answers didn't solve my problem, because I was looking for #OneToMany which isn't as good of a fit for the table structure I was going after. #ElementCollection is the right fit in my case. One of the gotchas of it I believe though is that it looks at the entire row of relations as being unique, not just the rows id.
#Entity
public class ParentObject {
#Column(nullable=false, updatable=false)
#Id #GeneratedValue(generator="...")
private String id;
#ElementCollection
#CollectionTable( name = "chidren", joinColumns = #JoinColumn( name = "parent_id" ) )
private List<ObjectChild> attrs;
...
}
#Embeddable
public static class ObjectChild implements Serializable {
#Column(nullable=false, updatable=false)
private String parentId;
#Column(nullable=false, updatable=false)
private String name;
#Column(nullable=false, updatable=false)
private int pos;
#Override
public String toString() {
return new Formatter().format("%s.%s[%d]", parentId, name, pos).toString();
}
... getters and setters REQUIRED (at least they were for me)
}
It seems that you got pretty close, and I am trying to do the same thing in my current system. I started with the surrogate key but would like to remove it in favor of a composite primary key consisting of the parent's PK and the index in the list.
I was able to get a one-to-one relationship that shares the PK from the master table by using a "foreign" generator:
#Entity
#GenericGenerator(
name = "Parent",
strategy = "foreign",
parameters = { #Parameter(name = "property", value = "parent") }
)
public class ChildObject implements Serializable {
#Id
#GeneratedValue(generator = "Parent")
#Column(name = "parent_id")
private int parentId;
#OneToOne(mappedBy = "childObject")
private ParentObject parentObject;
...
}
I wonder if you could add the #GenericGenerator and #GeneratedValue to solve the problem of Hibernate not assigning the parent's newly acquired PK during insertion.
After saving the Parent object, you have to explicitly set the parentId in the Child objects for the inserts on the Child objects to work.
After spending three days on this, I think I have found a solution, but to be honest, I don't like it and it can definitely be improved. However, it works and solves our problem.
Here is your entity constructor, but you could also do it in the setter method.
Also, I used a Collection object but it should be same or similar with List:
...
public ParentObject(Collection<ObjectChild> children) {
Collection<ObjectChild> occ = new ArrayList<ObjectChild>();
for(ObjectChild obj:children){
obj.setParent(this);
occ.add(obj);
}
this.attrs = occ;
}
...
Basically, as someone else suggested, we must first manually set all the children's parent id before saving the parent (along with all children)
I was badly looking for an answer but couldn't find a working solution. Though I had the OneToMany in parent correctly and ManyToOne in child correctly, during parent's save, child's key was not getting assigned, the auto-generated value from parent.
My problem was fixed upon adding an annotation javax.persistence.MapsId above the #ManyToOne mapping in the child entity (Java class)
#MapsId("java_field_name_of_child's_composite_key_that_needs_the_value_from_parent")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PARENT_ID", nullable = false, insertable = false, updatable = false)
private Parent parent;
This is on top of what was answered by #Pascal Thivent (answered on Apr 10 '10 at 1:40)
Please refer to the example code snippet in his post, earlier in this thread.
Thanks,
PJR.
Related
Hibernate inserts null even when field is not null in the object being saved
I am facing a weird issue where even though all fields are set in the java object, when I save the object hibernate tries to insert null values in the fields. When I further debugged, I saw that while merging the new entity at this line hibernate generates an empty object and sets to the target instead of setting given entity to the target. This results in insert query with null values. Am I missing some configuration here? Below are the example entities having associations similar to my case. class Vehicle { #Id #GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; #Column(nullable = false) #Enumerated(EnumType.STRING) #EqualsAndHashCode.Include private VehicleType vehicleType; #OneToOne(mappedBy="vehicle", fetch=FetchType.LAZY) private Car car; #OneToOne(mappedBy="vehicle", fetch=FetchType.LAZY) private Truck truck; } class Car { #Id private Integer id; #OneToOne(fetch = FetchType.LAZY, optional = false) #MapsId #JoinColumn(name = "vehicle_id") private Vehicle vehicle; ... } class Truck { #Id private Integer id; #OneToOne(fetch = FetchType.LAZY, optional = false) #MapsId #JoinColumn(name = "vehicle_id") private Vehicle vehicle; ... }
I encountered the same problem, in my case I have an application with: public class Claim extends BaseEntity<Integer> implements Serializable { #OneToOne(cascade = CascadeType.ALL) #JoinColumn(name = "claimdetailsid", referencedColumnName = "id") private ClaimDetails claimDetails; #OneToOne(cascade = CascadeType.PERSIST) #JoinColumn(name = "beneficiaryid", referencedColumnName = "id") private Beneficiary beneficiary; .... } When I saved the Claim entity, the Claim and ClaimDetails objects were inserted correctly. The other entities had all the fields null, except the id and the creation date. I tried changing CascadeType.PERSIST to CascadeType.ALL, that solved my insert problem. But the delete cascade doesn't work now.
JPA delete child without deleting parent
I am using Spring Boot 2.3.0. I have a ManyToOne relationship on one side and a OneToMany relationship on the other side. One parent to many children, but many children to one parent. I am trying to be able to delete children without affecting the parent. I have nullable = false on the child side for the parent field because I don't want to end up with accidental nulls for parent in the parent_to_child table. I want things like that to be enforced and get caught. When I do readerRepository.save(reader) after removing one of the TBRList items (this is the child) from the List<TBRList> in the Reader object (this is the parent), I keep getting an error about the parent field not being able to be null when trying to delete the child. If I set nullable to false on the parent field in the child object, my parent disappears. I thought I understood how this was supposed to work, but obviously not. I have: #Entity //parent public class Reader implements Serializable { #Id #GeneratedValue(strategy = IDENTITY) #JsonIgnore private Long id; #OneToMany(cascade = CascadeType.ALL, mappedBy = "reader", orphanRemoval = true) Set<TBRList> tbrLists = new HashSet<>(); //other fields, getters, setters, etc. } #Entity(name = "tbr") //child public class TBRList implements Serializable { #Id #GeneratedValue(strategy = IDENTITY) private Long id; #Column(nullable = false) private String name; #JsonIgnore #ManyToOne #JoinColumn(name = "reader_id", nullable = false) private Reader reader; //other fields, getters, setters, etc } In the below snippet, readerRepository.save(reader) is where the org.hibernate.PropertyValueException: not-null property references a null or transient value : com.me.project.entity.TBRList.reader exception is happening. if (reader.hasTBRList(tbrListName)) { Iterator<TBRList> it = reader.getTbrLists().iterator(); while (it.hasNext()) { TBRList tbrList = it.next(); if (tbrList.getName().equals(tbrListName)) { it.remove(); readerRepository.save(reader); break; } } } I tried to also set reader to null in TBRList and delete it via the tbrListRepository, but the same thing happened. In fact, I've tried too many things to remember them all (I try to ask questions as a last result after hours of searching and trying things). What am I doing wrong with trying to have a Parent/Child relationship, where I don't want Child.parent to be null, and I want to be able to delete a child from the parent without deleting the parent in the process?
I created the same classes and i get this result to execute as you want: #Entity(name = "tbr") #Data public class TBRList { #Id #GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; #Column(nullable = false) private String name; #JsonIgnore #ManyToOne(fetch = FetchType.EAGER) #JoinColumn(name = "reader_id", nullable = false) private Reader reader; } #Entity #Data public class Reader { #Id #GeneratedValue(strategy = GenerationType.IDENTITY) #JsonIgnore private Long id; #OneToMany(cascade = CascadeType.ALL, mappedBy = "reader", orphanRemoval = true) Collection<TBRList> tbrLists ; }
Does anybody know the usage of table attribute in #JoinColumn annotation? Should i give the actual table name or the entity name?
I have a problem in using #ManyToOne relation, because my foreign key and primary key have same name, so Hibernate is considering the one i mapped as the current table's column name. So i thought i will use table attribute of #JoinColumn annotations, but it seems to be not working. I gave actual table for it's value, but it is not taking. Tried the Class-name as well. below are the Entities. You can see PRJ_NBR is same in both tables. So when i try to run the project i'm getting error like Cannot find the expected secondary table: no HEAD available If I remove table attribute from #JoinColumn I'm getting error - Repeated column in mapping for entity: com.example.jpademo.Detail column: PRJ_NBR (should be mapped with insert="false" update="false") #Entity(name="Head") #Table(name = "HEAD") public class QuoteHead { #Id #Column(name = "PRJ_NBR") private Integer projNumber; #Column(name = "CUS_SYS_ID") private Integer cusSysId; #OneToMany(mappedBy = "head", cascade = CascadeType.ALL, orphanRemoval = true) private List<Detail> details = new ArrayList<Detail>(); } #Entity #Table(name = "DETAIL") #JsonIgnoreProperties public class Detail { #Transient private Integer projectNumber; #Transient private Integer itemNumber; #Transient private Integer sequenceNumber; #ManyToOne #JoinColumn(name = "PRJ_NBR", table = "HEAD") private Head head; #JsonIgnore #EmbeddedId private DetailCompositeId id; } #Embeddable public class DetailCompositeId implements Serializable { private static final long serialVersionUID = 1L; #Column(name = "PRJ_NBR") private Integer projectNumber; #Column(name = "ITM_NBR") private Integer itemNum; #Column(name = "SEQ_NBR") private Integer sequenceNumber; }
Remove 'table' and try putting insertable="false" , updatable="false" then I think it should work
You can utilize the #MapsId annotation. See this post: can someone please explain me #MapsId in hibernate? You can remove #JoinColumn in your #ManyToOne mapping and replace it with #MapsId, as shown below: #ManyToOne #MapsId("projectNumber") private Head head;
Hibernate JPA - Map to an embedded id [duplicate]
I'm using Hibernate with annotations (in spring), and I have an object which has an ordered, many-to-one relationship which a child object which has a composite primary key, one component of which is a foreign key back to the id of the parent object. The structure looks something like this: +=============+ +================+ | ParentObj | | ObjectChild | +-------------+ 1 0..* +----------------+ | id (pk) |-----------------| parentId | | ... | | name | +=============+ | pos | | ... | +================+ I've tried a variety of combinations of annotations, none of which seem to work. This is the closest I've been able to come up with: #Entity public class ParentObject { #Column(nullable=false, updatable=false) #Id #GeneratedValue(generator="...") private String id; #OneToMany(mappedBy="parent", fetch=FetchType.EAGER, cascade={CascadeType.ALL}) #IndexColumn(name = "pos", base=0) private List<ObjectChild> attrs; ... } #Entity public class ChildObject { #Embeddable public static class Pk implements Serializable { #Column(nullable=false, updatable=false) private String parentId; #Column(nullable=false, updatable=false) private String name; #Column(nullable=false, updatable=false) private int pos; #Override public String toString() { return new Formatter().format("%s.%s[%d]", parentId, name, pos).toString(); } ... } #EmbeddedId private Pk pk; #ManyToOne #JoinColumn(name="parentId") private ParentObject parent; ... } I arrived at this after a long bout of experimentation in which most of my other attempts yielded entities which hibernate couldn't even load for various reasons. UPDATE: Thanks all for the comments; I have made some progress. I've made a few tweaks and I think it's closer (I've updated the code above). Now, however, the issue is on insert. The parent object seems to save fine, but the child objects are not saving, and what I've been able to determine is that hibernate is not filling out the parentId part of the (composite) primary key of the child objects, so I'm getting a not-unique error: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.kpruden.ObjectChild#null.attr1[0]] I'm populating the name and pos attributes in my own code, but of course I don't know the parent ID, because it hasn't been saved yet. Any ideas on how to convince hibernate to fill this out? Thanks!
The Manning book Java Persistence with Hibernate has an example outlining how to do this in Section 7.2. Fortunately, even if you don't own the book, you can see a source code example of this by downloading the JPA version of the Caveat Emptor sample project (direct link here) and examining the classes Category and CategorizedItem in the auction.model package. I'll also summarize the key annotations below. Do let me know if it's still a no-go. ParentObject: #Entity public class ParentObject { #Id #GeneratedValue #Column(name = "parentId", nullable=false, updatable=false) private Long id; #OneToMany(mappedBy="parent", fetch=FetchType.EAGER) #IndexColumn(name = "pos", base=0) private List<ChildObject> attrs; public Long getId () { return id; } public List<ChildObject> getAttrs () { return attrs; } } ChildObject: #Entity public class ChildObject { #Embeddable public static class Pk implements Serializable { #Column(name = "parentId", nullable=false, updatable=false) private Long objectId; #Column(nullable=false, updatable=false) private String name; #Column(nullable=false, updatable=false) private int pos; ... } #EmbeddedId private Pk id; #ManyToOne #JoinColumn(name="parentId", insertable = false, updatable = false) #org.hibernate.annotations.ForeignKey(name = "FK_CHILD_OBJECT_PARENTID") private ParentObject parent; public Pk getId () { return id; } public ParentObject getParent () { return parent; } }
You should incorporate the ParentObject reference just into ChildObject.Pk rather than map parent and parentId separately: (getters, setters, Hibernate attributes not related to problem and member access keywords omitted) class ChildObject { #Embeddable static class Pk { #ManyToOne... #JoinColumn(name="parentId") ParentObject parent; #Column... String name... ... } #EmbeddedId Pk id; } In ParentObject you then just put #OneToMany(mappedBy="id.parent") and it works.
Firstly, in the ParentObject, "fix" the mappedBy attribute that should be set to "parent". Also (but this is maybe a typo) add an #Id annotation: #Entity public class ParentObject { #Id #GeneratedValue private String id; #OneToMany(mappedBy="parent", fetch=FetchType.EAGER) #IndexColumn(name = "pos", base=0) private List<ObjectChild> attrs; // getters/setters } Then, in ObjectChild, add a name attribute to the objectId in the composite key: #Entity public class ObjectChild { #Embeddable public static class Pk implements Serializable { #Column(name = "parentId", nullable = false, updatable = false) private String objectId; #Column(nullable = false, updatable = false) private String name; #Column(nullable = false, updatable = false) private int pos; } #EmbeddedId private Pk pk; #ManyToOne #JoinColumn(name = "parentId", insertable = false, updatable = false) private ParentObject parent; // getters/setters } AND also add insertable = false, updatable = false to the #JoinColumn because we are repeating the parentId column in the mapping of this entity. With these changes, persisting and reading the entities is working fine for me (tested with Derby).
After much experimentation and frustration, I eventually determined that I cannot do exactly what I want. Ultimately, I went ahead and gave the child object its own synthetic key and let Hibernate manage it. It's a not ideal, since the key is almost as big as the rest of the data, but it works.
Found this question searching for the answer to it's problem, but it's answers didn't solve my problem, because I was looking for #OneToMany which isn't as good of a fit for the table structure I was going after. #ElementCollection is the right fit in my case. One of the gotchas of it I believe though is that it looks at the entire row of relations as being unique, not just the rows id. #Entity public class ParentObject { #Column(nullable=false, updatable=false) #Id #GeneratedValue(generator="...") private String id; #ElementCollection #CollectionTable( name = "chidren", joinColumns = #JoinColumn( name = "parent_id" ) ) private List<ObjectChild> attrs; ... } #Embeddable public static class ObjectChild implements Serializable { #Column(nullable=false, updatable=false) private String parentId; #Column(nullable=false, updatable=false) private String name; #Column(nullable=false, updatable=false) private int pos; #Override public String toString() { return new Formatter().format("%s.%s[%d]", parentId, name, pos).toString(); } ... getters and setters REQUIRED (at least they were for me) }
It seems that you got pretty close, and I am trying to do the same thing in my current system. I started with the surrogate key but would like to remove it in favor of a composite primary key consisting of the parent's PK and the index in the list. I was able to get a one-to-one relationship that shares the PK from the master table by using a "foreign" generator: #Entity #GenericGenerator( name = "Parent", strategy = "foreign", parameters = { #Parameter(name = "property", value = "parent") } ) public class ChildObject implements Serializable { #Id #GeneratedValue(generator = "Parent") #Column(name = "parent_id") private int parentId; #OneToOne(mappedBy = "childObject") private ParentObject parentObject; ... } I wonder if you could add the #GenericGenerator and #GeneratedValue to solve the problem of Hibernate not assigning the parent's newly acquired PK during insertion.
After saving the Parent object, you have to explicitly set the parentId in the Child objects for the inserts on the Child objects to work.
After spending three days on this, I think I have found a solution, but to be honest, I don't like it and it can definitely be improved. However, it works and solves our problem. Here is your entity constructor, but you could also do it in the setter method. Also, I used a Collection object but it should be same or similar with List: ... public ParentObject(Collection<ObjectChild> children) { Collection<ObjectChild> occ = new ArrayList<ObjectChild>(); for(ObjectChild obj:children){ obj.setParent(this); occ.add(obj); } this.attrs = occ; } ... Basically, as someone else suggested, we must first manually set all the children's parent id before saving the parent (along with all children)
I was badly looking for an answer but couldn't find a working solution. Though I had the OneToMany in parent correctly and ManyToOne in child correctly, during parent's save, child's key was not getting assigned, the auto-generated value from parent. My problem was fixed upon adding an annotation javax.persistence.MapsId above the #ManyToOne mapping in the child entity (Java class) #MapsId("java_field_name_of_child's_composite_key_that_needs_the_value_from_parent") #ManyToOne(fetch = FetchType.LAZY) #JoinColumn(name = "PARENT_ID", nullable = false, insertable = false, updatable = false) private Parent parent; This is on top of what was answered by #Pascal Thivent (answered on Apr 10 '10 at 1:40) Please refer to the example code snippet in his post, earlier in this thread. Thanks, PJR.
How can I mark a foreign key constraint using Hibernate annotations?
I am trying to use Hibernate annotation for writing a model class for my database tables. I have two tables, each having a primary key User and Question. #Entity #Table(name="USER") public class User { #Id #Column(name="user_id") #GeneratedValue(strategy=GenerationType.AUTO) private Long id; #Column(name="username") private String username; // Getter and setter } Question Table. #Entity #Table(name="QUESTION") public class Questions extends BaseEntity{ #Id #Column(name="question_id") #GeneratedValue(strategy=GenerationType.AUTO) private int id; #Column(name="question_text") private String question_text; // Getter and setter } And I have one more table, UserAnswer, which has userId and questionId as foreign keys from the above two tables. But I am unable to find how I can reference these constraints in the UserAnswer table. #Entity #Table(name="UserAnswer ") public class UserAnswer { #Column(name="user_id") private User user; //#ManyToMany #Column(name="question_id") private Questions questions ; #Column(name="response") private String response; // Getter and setter } How can I achieve this?
#Column is not the appropriate annotation. You don't want to store a whole User or Question in a column. You want to create an association between the entities. Start by renaming Questions to Question, since an instance represents a single question, and not several ones. Then create the association: #Entity #Table(name = "UserAnswer") public class UserAnswer { // this entity needs an ID: #Id #Column(name="useranswer_id") #GeneratedValue(strategy = GenerationType.AUTO) private Long id; #ManyToOne #JoinColumn(name = "user_id") private User user; #ManyToOne #JoinColumn(name = "question_id") private Question question; #Column(name = "response") private String response; //getter and setter } The Hibernate documentation explains that. Read it. And also read the javadoc of the annotations.
There are many answers and all are correct as well. But unfortunately none of them have a clear explanation. The following works for a non-primary key mapping as well. Let's say we have parent table A with column 1 and another table, B, with column 2 which references column 1: #ManyToOne #JoinColumn(name = "TableBColumn", referencedColumnName = "TableAColumn") private TableA session_UserName; #ManyToOne #JoinColumn(name = "bok_aut_id", referencedColumnName = "aut_id") private Author bok_aut_id;
#JoinColumn(name="reference_column_name") annotation can be used above that property or field of class that is being referenced from some other entity.