The app's stack: Spring MVC, Spring DataJPA, Hibernate. There are three entities: student, tutor, theme.
Theme:
#Entity
#Table(name = "themes")
public class Theme {
// fields omitted
}
Student:
#Entity
#Table(name = "students")
public class Student {
private Map<Theme, Tutor> tutors;
// other fields omitted
}
Tutor:
#Entity
#Table(name = "tutors")
public class Tutor {
private Map<Theme, Student> students;
// other fields omitted
}
For save student-tutor-theme relationships i want use this table (PostgreSQL):
CREATE TABLE themes_students_tutors
(
theme_id INTEGER NOT NULL,
student_id INTEGER NOT NULL,
tutor_id INTEGER NOT NULL,
FOREIGN KEY (theme_id) REFERENCES themes (id) ON DELETE CASCADE,
FOREIGN KEY (student_id) REFERENCES students (id) ON DELETE CASCADE,
FOREIGN KEY (tutor_id) REFERENCES tutors (id) ON DELETE CASCADE
)
How i can to annotate tutors and students fields in entities, for their content correct persists in this table?
Like #kolossus mentioned: Use the #MapKeyJoinColumn¹ annotation, so that the classes (or the map fields) look like this (you can ignore the extention of AbstractPersistable):
Student:
public class Student extends AbstractPersistable<Long> {
#ManyToMany
#JoinTable(name = "themes_students_tutors", joinColumns = {
#JoinColumn(name = "student_id", referencedColumnName = "id") }, inverseJoinColumns = {
#JoinColumn(name = "tutor_id", referencedColumnName = "id") })
#MapKeyJoinColumn(name = "theme_id")
private Map<Theme, Tutor> tutors;
}
Tutor:
public class Tutor extends AbstractPersistable<Long> {
#ManyToMany
#JoinTable(name = "themes_students_tutors", joinColumns = {
#JoinColumn(name = "tutor_id", referencedColumnName = "id") }, inverseJoinColumns = {
#JoinColumn(name = "student_id", referencedColumnName = "id") })
#MapKeyJoinColumn(name = "theme_id")
private Map<Theme, Student> students;
}
Given that, something like this would be created:
Hibernate: create table students (id bigint not null, primary key (id))
Hibernate: create table themes (id bigint not null, primary key (id))
Hibernate: create table themes_students_tutors (tutor_id bigint not null, student_id bigint not null, theme_id bigint not null, primary key (student_id, theme_id))
Hibernate: create table tutors (id bigint not null, primary key (id))
Hibernate: alter table themes_students_tutors add constraint FKm5l4is34t5gs14p4skkv3aup7 foreign key (student_id) references students
Hibernate: alter table themes_students_tutors add constraint FK8o0mm5ywi0l4hdxi4lgw4dbnu foreign key (theme_id) references themes
Hibernate: alter table themes_students_tutors add constraint FKa0n6jvie0kmk0pmikcuvtepxh foreign key (tutor_id) references tutors
¹: See the Javadoc documentation of #MapKeyJoinColumn for some other samples
Related
These are the tables I intend to have in my database.
First Table
Second Table
Third table
#Entity
#Table(name = "STATIONS")
public class Station {
#Id
private Long stnCode;
}
#Entity
#Table(name = "TRAINS")
public class Train {
#Id
private String trainNo;
}
#Entity
#Table(name = "STOPS")
public class Stop {
#EmbeddedId
private StopId stopId;
}
#Embeddable
class StopId implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRAIN_NO")
private Train trainNo;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STN_CODE")
private Station stnCode;
}
Hibernate: create table STATIONS (stnCode bigint not null, primary key (stnCode))
Hibernate: create table STOPS (STN_CODE bigint not null, TRAIN_NO varchar(255) not null, primary key (STN_CODE, TRAIN_NO))
Hibernate: create table TRAINS (trainNo varchar(255) not null, primary key (trainNo))
Hibernate: alter table STOPS add constraint FK1431wv4cp0qef8drx65we3m03 foreign key (STN_CODE) references STATIONS
Hibernate: alter table STOPS add constraint FK5omkrq9vt17i1w6qose6njvhw foreign key (TRAIN_NO) references TRAINS
I have the roles field in User entity:
#Entity
#Table(indexes = {
#Index(columnList = "uuid")
})
public class User
...
#ElementCollection(fetch = FetchType.EAGER)
#Enumerated(EnumType.STRING)
#NotEmpty
private Set<Roles> roles;
when I try to delete user with a query, the referential integrity constraint violation occurs, because user is referenced from User_roles table.
How to solve this in any way?
DDL for related table shows
create or replace table User_roles
(
User_id bigint not null,
roles varchar(255) null,
constraint FKi81fp6mx433heb7dvbxqaqvpv
foreign key (User_id) references User (id)
);
i.e. it doesn't contain ON DELETE CASCADE clause. I need it be there.
You can add ON DELETE CASCADE clause to the FOREIGN KEY constraint in the following way:
import javax.persistence.ForeignKey;
#Entity
#Table(name ="User")
public class User
{
#ElementCollection
#CollectionTable(
name = "User_roles",
joinColumns = #JoinColumn(name = "User_id"),
foreignKey = #ForeignKey(
name = "user_fk",
foreignKeyDefinition = "FOREIGN KEY (User_id) REFERENCES User(id) ON DELETE CASCADE")
)
#Enumerated(EnumType.STRING)
private Set<Roles> roles;
}
I have below two tables:
`message` (
`id` varchar(150),
`Message` varchar(1000) ,
PRIMARY KEY (`id`)
)
fallback_status (
message_key varchar(150),
fallback_delivere` tinyint(1),
fallback_read tinyint(1),
fallback_answered tinyint(1),
PRIMARY KEY (message_key)
)
I don't have any foreign key relationship at database level. I have created two entity for these tables
#Entity
#Table(name = "message")
public class Message {
#Id
#Column(name = "id", unique = true)
private String key;
#Column(name = "message")
String message
#OneToOne
#PrimaryKeyJoinColumn(name = "id", referencedColumnName = "message_key")
private MessageFallbackStatus messageFallbackStatus;
}
and
#Entity
#Table(name = "fallback_status")
public class MessageFallbackStatus {
#Id
#Column(name="message_key")
private String messageKey;
#Column(name="fallback_delivered")
private boolean fallbackDelivered;
#Column(name="fallback_read")
private boolean fallbackRead;
#Column(name="fallback_answered")
private boolean fallbackAnswered;
}
With this configuration Hibernate not able to persist data in fallback_status table.
my questions are:
Is the foreign key relationship is mandatory at database level?
what would be the proper mapping for this scenario?
thanks for any help.
I have been migrating from hibernate 4 to hibernate 5. It is ok in hibernate 4, but doesn't work in hibernate 5.
I am getting exception:
Caused by: org.hibernate.MappingException: Foreign key
(FKf6eo63yo42ylh7vl5klap2eum:ProductParent [parent_id])) must have
same number of columns as the referenced primary key (ProductParent
[parent_id,product_id])
This is my hibernate mapping:
#Entity
public class ProductParent implements Serializable {
#Id
#OneToOne()
#JoinColumn(name = "product_id")
private AbstractProduct product = new AbstractProduct();
#ManyToMany(cascade = ALL, fetch = EAGER)
#JoinTable(name = PRODUCTPARENT, joinColumns = { #JoinColumn(name = "product_id") }, inverseJoinColumns = { #JoinColumn(name = "parent_id") })
private Set<ProductParent> parents = new HashSet<>();
and table structure:
CREATE TABLE productparent (
product_id bigint NOT NULL,
parent_id bigint,
CONSTRAINT fk_parent_id FOREIGN KEY (parent_id) REFERENCES abstractproduct (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_product_id FOREIGN KEY (product_id) REFERENCES abstractproduct (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT product_id_parent_id_should_be_unique UNIQUE (product_id, parent_id)
)
Could you help me that?
Solution:
To add:
#OneToOne
#JoinColumn(name = PARENT_ID)
private AbstractProduct parent = new AbstractProduct();
I have the following UML diagram.
Since it is a manyToMany relation i need three tables to store the data:
CREATE TABLE Users(
idObj BIGINT NOT NULL PRIMARY KEY,
nome VARCHAR(100),
nomeUtente VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL,
email VARCHAR(50) NOT NULL
);
CREATE TABLE Works(
idObj BIGINT NOT NULL PRIMARY KEY,
nrIncarico int,
annoIncarico int,
...
);
CREATE TABLE UsersWorksRel(
idGiudice BIGINT NOT NULL,
idIncarico BIGINT NOT NULL,
FOREIGN KEY (idGiudice) REFERENCES Users(idObj),
FOREIGN KEY (idIncarico) REFERENCES Works(idObj)
);
In the AbstractPO i used the #MappedSuperclass annotation, the Users also is ok, but i'm not able to annotate the Judge class...
My idea was to use the Judge class to have the manyToMany relation with the Works, like this:
public class Judge extends UserPO{
private List<Works> incarichi;
public Judge () {
setTipo(TipologiaUtente.GIUDICE);
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "UsersWorksRel", joinColumns = {
#JoinColumn(name = "idGiudice", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "idIncarico", nullable = false, updatable = false) })
public List<Works> getIncarichi() {
return incarichi;
}
public void setIncarichi(List<Works> incarichi) {
this.incarichi = incarichi;
}
}