Given 3 tables:
student (id)
student_to_class (student_id, class_id)
class (id)
I'd like to apply a where clause on the student_to_class where student_id = :studentId. I've found many examples that apply where clause on "class" table or "student" table, but not the many-to-many table.
The student table has a #ManyToMany
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "student_to_class",
joinColumns = { #JoinColumn(name = "student_id", nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "class_id", nullable = false) }
)
private Set<ClassEntity> classes;
The class table has a #ManyToMany
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "student_to_class",
joinColumns = { #JoinColumn(name = "class_id", nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "student_id", nullable = false) }
)
private Set<StudentEntity> students;
Here is the query I'm trying to translate into Criteria:
select * from student, student_to_class where student_to_class.student_id = 1 and student.id = student_to_class.class_id
I'm trying to figure out how to reference the many-to-many table since I don't have an actual class representing this table.
Criteria c = sessionFactory.getCurrentSession().createCriteria(ClassEntity.class);
c.createAlias("student_to_class", "entities"); // how to reference the student_to_class ?
c.add(Restrictions.eq("entities.user_id", studentEntity.getId()));
But I get an error, which makes sense to me, but I haven't had much luck fixing it:
could not resolve property: student_to_class
Since the studentid in the Student table will be the same as the studentid in the student_to_class table there is no need to filter by the join table. Simply run the where clause against student.student_id
Related
I hope you can help me on that.
Table A has a multi-column join to Table B where one of the JoinColumns can be nullable...
#Entity
#Table(name = "TABLE_A")
public class TableA {
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumns({
#JoinColumn(name = "KEY1_TABLE_A", referencedColumnName = "KEY1_TABLE_B"),
#JoinColumn(name = "KEY2_TABLE_A", referencedColumnName = "KEY2_TABLE_B"),
#JoinColumn(name = "GROUP_TABLE_A", referencedColumnName = "GROUP_TABLE_B", nullable = true)})
private TableB typeB;
}
In TableB object the columns
TABLE_B#KEY1_TABLE_B (not null)
TABLE_B#KEY2_TABLE_B (not null)
TABLE_B#GROUP_TABLE_B (nullable)
are mapped as Strings.
The touple KEY1_TABLE_B /KEY2_TABLE_B /GROUP_TABLE_B is a unique key.
The generated SQL is as follows (shortened)
SELECT
*
FROM
table_a this_
INNER JOIN table_b b_ ON
this_.KEY1_TABLE_A = b_.KEY1_TABLE_B AND
this_.KEY2_TABLE_A = b_.KEY2_TABLE_B AND
this_.GROUP_TABLE_A = b_.GROUP_TABLE_B <-- here is the issue: works only with "is not null" on Oracle
WHERE
this.XYZ=<some-conditions-here>;
if i would write the SQL directly it should be something like
on ... AND (
(this_.GROUP_TABLE_A = b_.GROUP_TABLE_B)
OR (this_.GROUP_TABLE_A is null and b_.GROUP_TABLE_B is null)
)
Thanks for your thoughts and ideas!
to-many tables mapped like this :
Resume.java :
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JsonIgnore
#JoinTable(
name = "resume_skills",
joinColumns = #JoinColumn(name = "skill_id"),
inverseJoinColumns = #JoinColumn(name = "resume_id"))
private List<Skill> skills = new ArrayList<Skill>();
public void addSkill(Skill skill) {
skills.add(skill);
skill.getResumes().add(this);
}
Skill.java
#ManyToMany(mappedBy="skills")
#JsonIgnore
private List<Resume> resumes;
I do this :
Resume resumeToAdd = new Resume(resume.getGithubAdress(),
resume.getLinkedinAdress(),
resume.getCoverLetter(),
resume.getPicture(),
employee
);
resumeDao.save(resumeToAdd);
Skill skill = skillService.findById(1).getData();
System.out.println(skill);
resumeToAdd.addSkill(skill);
resumeDao.save(resumeToAdd);
But it occurs an error, for example it added a Resume with id 60 and it's trying to add mapping with skill id 60 But it cant because there is no skill in database with id of 60, it should be 1. What did i miss here?
Looks like you mixed up the order of the mapping. It should be this:
#JoinTable(
name = "resume_skills",
joinColumns = #JoinColumn(name = "resume_id"),
inverseJoinColumns = #JoinColumn(name = "skill_id"))
My code is as below. I am using the spring boot with jpa and postgresql database
I need user friendly name as foreign key.
#Entity
#Table(name="course_table")
public class Course extends BaseAuditingEntity {
#ManyToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
#JoinTable(name = "course_program_table", joinColumns = #JoinColumn(name = "course_id", referencedColumnName = "course_id", foreignKey = #ForeignKey(name = "fk_program_id")), inverseJoinColumns = #JoinColumn(name = "program_id", referencedColumnName = "program_id", foreignKey = #ForeignKey(name = "fk_course_id")))
private List programs;
}
I have given the name of foreign key using the #ForeignKey annotation but when I see db it is showing the randomly created foreignkey name.
CREATE TABLE course_program_table
(
course_id integer NOT NULL,
program_id integer NOT NULL,
CONSTRAINT fk_28c95hl4nqclyvyxuduei5nbf FOREIGN KEY (program_id)
REFERENCES public.program_table (program_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT fk_5sainywquv8yyu24pjk3jptn7 FOREIGN KEY (course_id)
REFERENCES public.course_table (course_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
I need foreign key as mentioned in the annotation like fk_program_id and fk_course_id.
Thanks in advance.
With a join table this is how you should specify it
#ManyToMany
#JoinTable(name = "course_program_table",
joinColumns = #JoinColumn(name = "course_id", ...)
foreignKey = #ForeignKey(name = "fk_program_id"),
inverseJoinColumns = #JoinColumn(name = "program_id", ...)
inverseForeignKey = #ForeignKey(name = "fk_course_id"))
private List programs;
This is how I do it with the JPA provider I use (not Hibernate), and that is why the #JoinTable has the "foreignKey"/"inverseForeignKey" attributes (the FKs are on/owned by the join table).
If that doesn't work then you need to be looking at raising a bug on your chosen JPA provider.
#ManyToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
#JoinTable(name = "tten_courseservice_course_program_table", joinColumns = #JoinColumn(name = "course_id", referencedColumnName = "course_id"), inverseJoinColumns = #JoinColumn(name = "program_id", referencedColumnName = "program_id"))
#ForeignKey(name="fk_tten_courseservice_course_table_course_id",inverseName="fk_tten_courseservice_program_table_program_id")
private List<ProgramEntity> programs;``
I have tried this and now I am able to generate foreign key name properly.
Hope it will help other.
I am trying to persist a OneToMany parent child relation with Join table, but in insert sql for join table only one column is considered (out of two).
insert into ITEM_BIDS_REL (BID_ID) values (?)
It does not include ITEM_ID column and due to that getting below error.
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("BIDDING_SYSTEM_OWNER"."ITEM_BIDS_REL"."ITEM_ID")
Two question here:
Why it only includes BID_ID column in INSERT query for ITEM_BIDS_REL join table.
Is the right way to design JOIN TABLE like I have kept BID_ID ad PK,FK and ITEM_ID as FK.
Use case:
Referring the "Online Action (bidding) System" example from Java Persistence with Hibernate book.
An Item can have many Bids on it.
ITEM table
ITEM_ID PK
NAME
INITIAL_AMOUNT
ITEM_BIDS table
BID_ID PK
AMOUNT
ITEM_BIDS_REL Join Table
BID_ID PK (FK from ITEM_BIDS table)
ITEM_ID NOT NULL (FK from ITEM table)
Entity classes:
Item Class
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable( name = "ITEM_BIDS_REL",
joinColumns = #JoinColumn(name = "ITEM_ID"),
inverseJoinColumns = #JoinColumn(name = "BID_ID"))
#JsonIgnore
private Set<Bid> bids;
Bid class
#ManyToOne(cascade = CascadeType.ALL)
#JoinTable(name = "ITEM_BIDS_REL",
joinColumns = {#JoinColumn(name = "BID_ID", insertable = false,
updatable = false)},
inverseJoinColumns = {#JoinColumn(name="ITEM_ID", insertable = false,
updatable = false)})
private Item item;
Persistence logic:
public Item addBid(BidDTO bidDTO) {
Item item = itemsRepository.findOne(bidDTO.getItemId());
Bid bid = Bid.builder()
.item(item)
.bidAmount(bidDTO.getBidAmount())
.build();
if(item.getBids() == null){
item.setBids(new HashSet<>());
}
item.getBids().add(bid);
bidRepository.save(bid);
itemsRepository.save(item);
return item;
}
I have a productJob table and a quadrat table. Every quadrat can be installed on many productJob and every productJob can have between 1 and 4 quadrats of the same or different kinds! I'm interested to keep the order of quadrat installation on the product jobs. For example first, second, third or forth place! But the following mapping doesn't create the order column on the JoinTable telai_quadrati. What is the problem of my mapping? The orderColumn isn't created in anyway!
#Entity
#Table(name = "telai")
public class ProductJob implements IProductJob, IProductJobProcessing{
#Embedded private QuadratGroup quadrateGroup = new QuadratGroup();
}
#Embeddable
public class QuadratGroup implements Serializable{
#OneToMany(targetEntity = Quadrat.class, cascade = CascadeType.ALL)
#JoinTable(
name = "telai_quadrati",
joinColumns = {#JoinColumn(name = "dbId", table = "telai")},
inverseJoinColumns = {#JoinColumn(name = "id", table = "quadrati")})
//#OrderColumn(name = "order")
#IndexColumn(name = "order")
public List<Quadrat> getQuadratList(){ //return an ordered list of the quadrats with at most 4 elements}
And it is clear that for the quadrats there exists no order so I use set!
#Entity
#Table(name = "quadrati")
public class Quadrat implements IQuadrat, Cloneable, Serializable{
#ManyToMany
#JoinTable(
name = "telai_quadrati",
joinColumns = #JoinColumn(name = "id", table = "quadrati"),
inverseJoinColumns = #JoinColumn(name = "dbId", table = "telai"))
private Set<ProductJob> productJobs;
It works if I use property access inspite of method access! Like this:
#OneToMany(targetEntity = Quadrat.class, cascade = CascadeType.ALL)
//#MapKeyJoinColumn(name="indice" , table = "telai_quadrati")
#JoinTable(
name = "telai_quadrati",
joinColumns = {#JoinColumn(name = "telaio_id", table = "telai")},
inverseJoinColumns = {#JoinColumn(name = "quadrato_id", table = "quadrati")})
#OrderColumn(name = "indice")
private List<Quadrat> quadratList;
But I wonder why it doesn't work with method access that forces me a heavy refactor in my project! :(