I have one table for person "id, gender, first_name,...".
The persons who should meet are saved in a second table named linked. A person can meet with another person only once. This table has the columns id1, id2, status and comment. Id1 and id2 are the IDs from the table person and here foreign keys, and both together are the primary key of the table linked.
I would like to join the linked data in the Java class Person.
But I don't know how to create the join, because the ID of the person can be contained in ID1 or in ID2.
Example:
Person
|ID|GENDER|FIRSTNAME|
|1 | m | name1 |
|2 | w | name2 |
|3 | m | name3 |
Linked
|ID1|ID2|status|
|1 | 2 | xy |
|1 | 3 | abc |
|2 | 3 | xyz |
For the person 1 I want IDs 2 and 3. For the person 2 I want the IDs 1 and 3.
SQL like:
select * from linked where id1=2 or id2=2
Result:
|ID1|ID2|status|
|1 | 2 | xy |
|2 | 3 | xyz |
Class Person
@ManyToMany
@JoinTable(name="linked",
joinColumns={@JoinColumn
private List<Linked> linked;
You should have three tables:
person
( id
, gender
, first_name
)
meet
( id
, status
, comment
)
linked
( meet_id
, person_id
)
and then you can use ManyToMany like this:
@ManyToMany(mappedBy = "persons")
Set<Meet> meets;
@JoinTable(
name = "linked",
joinColumns = @JoinColumn(name = "meet_id"),
inverseJoinColumns = @JoinColumn(name = "person_id"))
Set<Person> persons;
By this way, if later a meet
can have multiple person
, you can just add more record to the linked
table, instead of add more columns.
This relation looks like many to many recursive relationship
where many persons can meets other persons.
The easiest way to implement this relation is using @ManyToMany
with @JoinTable
annotations but the problem with this implementation is you can't attaching status
and comment
attributes to the generated table.
To implement this relationship clearly you must follow the following steps:-
1- create a composite key class represents the composition of ID1
and ID2
keys
@Embeddable
public class MeetId implements Serializable {
@Column(name = "ID1")
private int firstPersonId;
@Column(name = "ID2")
private int secondPersonId;
public MeetId() {}
public MeetId(int firstPersonId, int secondPersonId) {
this.firstPersonId = firstPersonId;
this.secondPersonId = secondPersonId;
}
public int getFirstPersonId() {
return firstPersonId;
}
public void setFirstPersonId(int firstPersonId) {
this.firstPersonId = firstPersonId;
}
public int getSecondPersonId() {
return secondPersonId;
}
public void setSecondPersonId(int secondPersonId) {
this.secondPersonId = secondPersonId;
}
}
2- create meet
class to represent meets
relation.
@Entity
@Table(name = "meet")
public class Meet {
@EmbeddedId
private MeetId id = new MeetId();
@MapsId("firstPersonId")
@ManyToOne
@JoinColumn(name = "ID1")
private Person id1;
@MapsId("secondPersonId")
@ManyToOne
@JoinColumn(name = "ID2")
private Person id2;
private String status;
private String comment;
public Meet() {}
public Meet(Person id1, Person id2) {
this.id1 = id1;
this.id2 = id2;
}
public Meet(Person id1, Person id2, String status) {
this.id1 = id1;
this.id2 = id2;
this.status = status;
}
public Meet(Person id1, Person id2, String status, String comment) {
this.id1 = id1;
this.id2 = id2;
this.status = status;
this.comment = comment;
}
public Person getId1() {
return id1;
}
public void setId1(Person id1) {
this.id1 = id1;
}
public Person getId2() {
return id2;
}
public void setId2(Person id2) {
this.id2 = id2;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
3- create person
entity and make a relation between it and meet
entity
@Entity
@Table(name = "person")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "first_name")
private String firstName;
private char gender;
@OneToMany(mappedBy = "id1", cascade = CascadeType.ALL)
private List<Meet> meets;
public Person() {}
public Person(String firstName, char gender) {
this(0, firstName, gender);
}
public Person(int id, String firstName, char gender) {
this.id = id;
this.firstName = firstName;
this.gender = gender;
this.meets = new LinkedList<>();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public List<Meet> getMeets() {
return meets;
}
public void setMeets(List<Meet> meets) {
this.meets = meets;
}
public void addMeet(Person person, String status, String comment) {
meets.add(new Meet(this, person, status, comment));
}
public boolean removeMeet(Person person) {
return meets.stream()
.filter(meet -> meet.getId2().getId() == person.getId())
.findFirst()
.map(meets::remove)
.orElse(false);
}
}
After performing the above steps, you will have correctly presented the relationship in jpa.
Now let's create the CRUD methods:-
1- to store persons
public void addPerson(Person person) {
entityManager.getTransaction().begin();
entityManager.persist(person);
entityManager.getTransaction().commit();
}
2- to add meet
public void addMeet(int personId1, int personId2, String status, String comment) {
entityManager.getTransaction().begin();
Person person1 = entityManager.find(Person.class, personId1);
Person person2 = entityManager.find(Person.class, personId2);
person1.addMeet(person2, status, comment);
entityManager.getTransaction().commit();
}
3- to find all meets by id where ID1=id or ID2=id
Using CriteriaQuery
private static List<Meet> findAllMeetsWhereID1EqualsOrID2Equals(int personId) {
CriteriaBuilder cBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Meet> linkedCriteria = cBuilder.createQuery(Meet.class);
Root<Meet> linkedRoot = linkedCriteria.from(Meet.class);
linkedCriteria.select(linkedRoot).where(cBuilder.or(
cBuilder.equal(linkedRoot.get("id1"), personId),
cBuilder.equal(linkedRoot.get("id2"), personId)
));
return entityManager.createQuery(linkedCriteria).getResultList();
}
4- to find all meets by id where ID1=id or ID2=id
using createNativeQuery
method
private static List<Meet> findAllMeetsWhereID1EqualsOrID2Equals(int personId) {
String sql = "select * from meet where ID1=:id or ID2=:id";
Query query = entityManager.createNativeQuery(sql, Meet.class);
query.setParameter("id", personId);
return query.getResultList();
}
Check this link to get more information's about Many to Many using a composite key
First of all, thank you very much for the answers. They have definitely improved my understanding of the subject. However, I have not described my problem correctly I just realized.
Maybe I have a data modelling problem. Actually I want to map the following:
For further meets it is relevant to know with which persons a person already had a "meet" phase.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.