One-to-many join on composite primary key in jpa - java

I have search whole day but couldn't find the solution.
I have 2 entities Table A and Table B. Table A has 1 primary key and Table B has composite key. There is oneToMany mapping between Table A and Table B
I have created Table A Like below
#Entity
public class TableA {
#Id
private Integer sId;
private Integer roleNo;
private String studentName;
#OneToMany
#JoinColumn(name="roleNo")
private List<TableB> tableb;
}
Table B looks like below
#Entity
public class TableB {
#EmbededId
private CKStudent student;
private String activities;
}
here is my composite class
#Embeddable
public class CKStudent {
private Integer roleNo;
private Integer ActivityId;
}
I want to create query like this
select *
from tableA a
left join tableB on a.roleNo = b.roleNo
where a.sId = 1 and b.activityId = 3
I have written jpa method for it
List<TableA> findBySIdAndtablebStudentActivityId(Integer id,Integer activityId);
but I am not getting the required result,
I am getting result for all the activityId, and not the activityId which I am passing through parameter.
Any help would be appreciated.
UPDATE
This JPA is creating 2 queries
Query #1
select
tbla0_.sId as s_id1_8_, tbla0_.roleNo as rol2_8_,
tbla0_.studentName as student_name3_8
from tableA tbla0_
left outer join tableB tbl1_ on tbla0_.role_id = tbl1_.role_id
where tbla0_.sId = ?
and tbl1_.activityId = ?
which is the correct query
Query #2
select
tblB1_.roleNo as roleNo_21_0_, tblB1_.activityId as activityId2_21_0_,
tblB1_.activities as act1_21_1_,
from tableB tblB1_
where tblB1_.roleNo = ?
which is wrong and returning wrong results.

Related

How to ignore some column when join tables in Hibernate?

Hello This is my 2 tables:
record and submission.
In submission, it has 1 composite primary key:(submission_id, question_id). One submission number can have several questions number. For example:
And as for record, it has a composite primary key:(student_id, exam_id). It looks like this:
I want to join these 2 tables like MySQL:
select * from record
left join submission
on record.submission_id = submission.submission_id.
But in hibernate, I have successfully join these 2 tables, but it gives me the following hql:
Hibernate:
select
...all columns...
from
record record0_
inner join
submission submission1_
on record0_.submission_id=submission1_.submission_id
and record0_.question_id=submission1_.question_id
where
1=1
In this case, I will get 0 rows in the result.
I don't want it use "and record0_.question_id=submission1_.question_id" after on clause, because there is no question_id in my record table.
But I have to add all primary keys into the #joinColumns() when I add Submission attribute in Record class, like this:
// Record class
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "record")
public class Record implements java.io.Serializable{
private static final long serialVersionUID = 1L;
// Other columns I don't need to show
#Column(name = "submission_id")
private Integer submissionId;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "submission_id", referencedColumnName = "submission_id",insertable=false, updatable=false),
#JoinColumn(name = "question_id", referencedColumnName = "question_id",insertable=false, updatable=false)
})
private Submission submission;
}
My Submission class like this:
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "submission")
public class Submission implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name = "submission_id")
private Integer submissionId;
#Id
#Column(name = "question_id")
private Integer questionId;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "submission")
private Record record;
}
Anyone can give me some advice?
-------- How I combine these tables-------
Actually, I join 4 tables and all these joins have the same problem declared above.
Code below is how i combine these 4 tables (record, submission, question, optional)
#Override
public List<RcdSubQuesOpt> getRcdSubQuesOpt(int studentID, int examId) {
Session session = this.getSession();
// RcdSubQuesOpt --> this is a class to store attributes from different tables(classes)
List<RcdSubQuesOpt> results;
Transaction transaction = null;
transaction = session.beginTransaction();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<RcdSubQuesOpt> criteriaQuery = criteriaBuilder.createQuery(RcdSubQuesOpt.class);
// To combine these tables use join
Root<Record> pRoot = criteriaQuery.from(Record.class);
Join<Record, Submission> rcd2sub = pRoot.join(Record_.submission);
Join<Submission, Question> sub2que = rcd2sub.join(Submission_.question);
Join<Question, Optional> que2opt = sub2que.join(Question_.optional);
// Attributes in RcdSubQuesOpt class
// get these columns from result and assign them to RcdSubQuesOpt class
criteriaQuery.multiselect(
pRoot.get("studentId"),
pRoot.get("examId"),
rcd2sub.get("questionId"),
rcd2sub.get("stuAnswer"),
sub2que.get("content"),
que2opt.get("content"),
que2opt.get("answer"));
// Predicate predicate = pRoot.get("examId").equals(1);
criteriaQuery.where();
results = session.createQuery(criteriaQuery).getResultList();
transaction.commit();
return results;
}
You haven't mentioned how you retrieve that data using hibernate. Have you tried trying to use #Query (select r from Record left join Submission sub on r.submissionId = sub.id where ...") ?
you have defined a #OneToOne relation in your record class. Apparantly thats wrong, since there exists more then one entry in your submission table for one record. So change this to #OneToMany and the respective relation in the submission class to #ManyToOne.
Besides your entities are not well named and mapped. Submission is in fact more of a question or an answer to it, because a line in that table does not represent one submission, which would be the expected meaning.

JPA include additional columns from other tables in a query

I have an entity table, which does not associate to another two tables. Now I have a requirement to include also two columns, one from each of these tables, together with my entity in a response/dto.
As there is no association between the tables, I do not want to add the joins in my entity but just a special query. Is there a clean way to do so?
e.g.
#Entity
public class MyEntity {
#Id private Integer id;
#Column private String name;
#Column private String other;
}
public interface MyEntityRepo extends Repository<MyEntity, Integer> {
#Query("select a.info, b.desc, m.id, m.name, m.other from MyEntity m join TableA a on m.name = a.name join TableB b on m.name = b.name order by m.id")
List<MyEntityPlus> findAllPlus();
}
I tried using projection to create an interface MyEntityPlus like below, but it does not seem to work.
public interface MyEntityPlus {
String getInfo(); // from TableA
String getDesc(); // from TableB
Integer getId(); // from MyEntity
String getName(); // from MyEntity
String getOther(); // from MyEntity
}

embedded ids: primary key and foreign key

Given entity with embedded id and embedded foreign key:
#Entity
public class One {
#EmbeddedId
private ModelId id;
#Embedded
#AttributeOverride(name = "id", column = #Column(name = "two_id"))
private ModelId twoId;
}
#Embeddable
public class ModelId {
private Integer id;
}
when in JPQL:
SELECT o.id FROM One o WHERE o.twoId IN :twoId
then JPA generates SQL:
SELECT id FROM one WHERE id IN (?)
instead of:
SELECT id FROM one WHERE two_id IN (?)
How to make it work?
put the keys inside ModelID entity and use a reference of it as PK inside entity One:
#Entity
public class One {
#EmbeddedId
protected ModelId modelPK;
//getter and setter
}
public class ModelId {
#column(name="id")//give the real column name
private int id;
#column(name="towID")//give the real column name
private int twoId;
//getters and setters
}
and then use below JPQL query:
SELECT o.modelPK.id FROM One o WHERE o.modelPK.twoId=:twoId

JPQL Left Join - how to set up entity relationship in entity classes

Two tables:
TABLE_1:
REC_ID
1
2
3
4
TABLE_2:
REC_ID REC_VAL
2 A
3 B
Entity classes (basic structure):
#Entity
#Table(name="TABLE_1")
public class Entity1 {
#Id
#Column(name="REC_ID")
private String recId;
//getters and setters
}
#Entity
#Table(name="TABLE_2")
public class Entity2 {
#Id
#Column(name="REC_ID")
private String recId;
#Column(name="REC_VAL")
private String recVal;
//getters and setters
}
SQL Query and result:
SELECT T1.REC_ID, T2.REC_VAL FROM TABLE_1 T1 LEFT OUTER JOIN TABLE_2 T2 ON T1.REC_ID = T2.RED_ID
Result:
REC_ID REC_VAL
1 null
2 A
3 B
4 null
JPQL Query:
SELECT e1.recId, e2.recVal FROM Entity1 e1 LEFT JOIN e1.<an Entity2 field in Entity1*>
* I know I don't have it in the given structure above, but I want to know how to do it right. And how do I choose from #ManyToOne, #OneToOne, etc.
How do I modify the Entity classes and the JPQL query to achieve the same result as the SQL query? I've been trying various things, nothing works. It wouldn't allow me to create two fields with the same column name, or to define the String as the #JoinColumn. I almost got it working, but the generated SQL query contains a reference to REC_ID_REC_ID column in TABLE_2 which doesn't exist. And after Googling so much, I can't find a proper guide for this (ignoring that JPQL does not support in-line join conditions!)
You need to have a OneToOne association between the entities. And the association, on the owning side, must be annotated with #MapsId. Here's an example taken from the Hibernate documentation, which maps to your use-case:
#Entity
public class Body {
#Id
public Long getId() { return id; }
#OneToOne(cascade = CascadeType.ALL)
#MapsId
public Heart getHeart() {
return heart;
}
...
}
#Entity
public class Heart {
#Id
public Long getId() { ...}
}
Once you have that, you can use a query such as
select b.foo, h.bar from Body b left join b.heart h where ...

Hibernate Criteria for Join Table

Help me Hibernate Guru..
i have 2 relationship class, let's call class A and B
#Entity
#Table(name="A")
public class A extends Serializable{
#Id
#Column(name="a_id")
private int id;
#Column(name="a_name")
private String name;
/*
*.....Setter and Getter
*/
}
#Entity
#Table(name="B")
public class B extends Serializable{
#Id
#Column(name="b_id")
private int id;
#ManyToMany(
fetch= FetchType.EAGER,
targetEntity=package.A.class,
cascade={CascadeType.ALL}
)
#JoinTable(
name="B_A",
joinColumns=#JoinColumn(name="b_id"),
inverseJoinColumns=#JoinColumn(name="a_id")
)
#Fetch(FetchMode.SUBSELECT)
private List<A> list;
/*
*.....Setter and Getter
*/
}
Hibernate will generate 3 Table A, B, and B_A. with table B_A have 2 foreign key, one foreign key for primary key table A and one again foreign key for primary key table B,
i want select data from table A, like query :
select * from A a inner join B_A ba on ba.a_id = a.id inner join B b on b.b_id = ba.b_id where b.id in(?, ?, ?, ?)
so how Criteria code i have to create???? and for expected list result List i want to use Transformer.
Thanks
Try this:
criteria.createCriteria(A.class)
.createCriteria("id", "join_between_a_b")
.add(Restrictions.eq("some_field_of_A", someValue));
Remember, A and B have to have id as their identifiers in order to make them join.
By some_field_of_A I mean anything you like in class A, like name for example. You can have restriction over any properties of these classes.

Categories

Resources