How do I map a triple date map to a bi-directional relationship?
I read: JPA: How to map a card with a date as a key , but I have the opposite of a question, I have a value component Map
as a date. How do I display this? Map: Map<Club, java.util.Date>
Can you show an example that includes the code for the Club class? It should be noted that this is a triple display. I'm not sure if it matters or not, Club
and Clubber
also have bi-directional communication ManyToMany
. My initial guess was this:
public class Clubber{
@Id
@Column(name = "Clubber_Id")
private final int id;
@Temporal(TemporalType.TIMESTAMP)
@ElementCollection
@MapKeyJoinColumn(name = "id")
private final Map<Club, Date> joinDate;
@ManyToMany(cascade = CascadeType.ALL)
private final Collection<Club> clubs;
}
public class Club {
@Id
@Column(name = "Club_ID")
private final int id;
@ManyToMany(cascade = CascadeType.ALL, mappedBy = "clubs")
private final Collection<Clubber> clubbers;
}
Main:
Map<Club, Date> dates = randomGeneration(Date.class);
Collection<Club> clubs = randomGeneration(Club.class);
Clubber clubber = new Clubber(clubs, dates);
Club club = new Club(Arrays.asList(clubber));
session.saveOrUpdate(club);
The exception I get when I try to save Club
with multiple Clubbers
in it:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Club
Disappears @Transient
when added to the Clubber
joinDate
exception.
source to share
This is how your entities look like:
@Entity(name = "Clubber")
public class Clubber{
@Id
@GeneratedValue
@Column(name = "Clubber_Id")
private Integer id;
@Temporal(TemporalType.TIMESTAMP)
@ElementCollection
@CollectionTable(name="CLUB_ASSIGNMENTS", joinColumns=@JoinColumn(name="Clubber_Id", referencedColumnName="Clubber_Id"))
@Column(name="CLUB_DATE")
@MapKeyJoinColumn(name = "Club_ID", referencedColumnName="Club_ID")
private Map<Club, Date> joinDate = new HashMap<>();
public Integer getId() {
return id;
}
public Map<Club, Date> getJoinDate() {
return joinDate;
}
public Collection<Club> getClubs() {
return joinDate.keySet();
}
public void addClub(Club club) {
joinDate.put(club, new Date());
//clubs.add(club);
club.getClubbers().add(this);
}
}
@Entity(name = "Club")
public class Club {
@Id
@GeneratedValue
@Column(name = "Club_ID")
private Integer id;
@ManyToMany(mappedBy = "joinDate", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Clubber> clubbers = new ArrayList<>();
public Integer getId() {
return id;
}
public List<Clubber> getClubbers() {
return clubbers;
}
}
These are the tables that this mapping generates:
create table CLUB_ASSIGNMENTS (Clubber_Id integer not null, CLUB_DATE timestamp, Club_ID integer not null, primary key (Clubber_Id, Club_ID))
create table Club (Club_ID integer generated by default as identity (start with 1), primary key (Club_ID))
create table Clubber (Clubber_Id integer generated by default as identity (start with 1), primary key (Clubber_Id))
alter table CLUB_ASSIGNMENTS add constraint FK_i1d8m16i8ytv7jybg8aneo9hj foreign key (Club_ID) references Club
alter table CLUB_ASSIGNMENTS add constraint FK_6oitm1mry43ga5iovtfamp3q3 foreign key (Clubber_Id) references Clubber
alter table CLUB_ASSIGNMENTS add constraint FK_3xj613grja6o0xkjeb7upms4 foreign key (CLUB_DATE) references Club
This is how you link Clubber
to Club
:
final Clubber clubberReference = doInTransaction(session -> {
Clubber clubber = new Clubber();
Club club = new Club();
clubber.addClub(club);
session.persist(club);
return clubber;
});
doInTransaction(session -> {
Clubber clubber = (Clubber) session.get(Clubber.class, clubberReference.getId());
assertEquals(1, clubber.getClubs().size());
assertEquals(1, clubber.getJoinDate().size());
});
I created a test on GitHub to test this and it works:
insert into Club (Club_ID) values (default)
insert into Clubber (Clubber_Id) values (default)]
insert into CLUB_ASSIGNMENTS (Clubber_Id, Club_ID, CLUB_DATE) values (1, 1, '2015-06-10 16:37:36.487')
source to share
In fact, the exception indicates that when the list of objects is saved, the Club
object Clubber
(collection clubbers) is not saved. The code where you save the Club, before saving Club
you need to save each one Clubber
in it, then call save
for Club
.
The @Transient annotation is used to indicate that the field is not stored in the database. why don't you get exceptions after applying @Transient
.
source to share