Get complete Joining Object using Criteria Builder - java

select s.student_name, teach from STUDENTS_TEACHER as sl
inner join STUDENT as s on sl.id = s.stud_id
inner join TEACHER as teach on sl.id = teach.teach_id
I am trying to get StudentName and Teacher.class entity in the above query.
Here STUDENTS_TEACHER is mapping each Student_id with Teacher_Id
How can I get the same using CriteraBuilder
Root<StudentTeacherMapping> studentTeacherMapping =criteriaQuery.from(StudentTeacherMapping.class);
Join<StudentTeacherMapping, Student> studentJoin = attributeCategoryMappingRoot.join("student");
Join<StudentTeacherMapping, Teacher> teachJoin = attributeCategoryMappingRoot.join("teacher");
criteriaQuery.multiselect(studentJoin.get("StudentName"), Teacher.get("TeacherSub"), ? );
How can I get the Teacher Object for here?

Related

Using #EntityGraph with JPA constructor expressions

I have a query that uses a constructor expression. For the most part it works, but I wanted to reduce the number of queries on the database. So I tried FETCH and #EntityGraph, but I am getting
org.springframework.dao.InvalidDataAccessResourceUsageException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy ...
I tried removing the FETCH and just use JOIN to fix the problem, but it does not do the fetch operation.
Is this even allowed or possible with Hibernate/JPA?
Code wise it looks something like
#Query("select new example.BillingTargetAndStudent(bt,s) from Student s, BillingTarget bt where s.id = bt.targetID and bt.account.status = :accountStatus and bt.account.organization = :organization")
Stream<BillingTargetAndStudent> streamAllByOrganizationAndStatusForStudentList(Organization organization, AccountStatus accountStatus);
What I want to do is FETCH bt.account in the same query along with s.user.attributes. The bt.account isn't too hard to workaround, but the s.user.attributes would not be possible with the constructor expression as it is a collection
What I ended up doing is to use the Stream<Object[]> and select bt, s from ... then have a converter that changes Object[] to call the constructor expression
default Stream<BillingTargetAndStudent> streamAllByOrganizationAndStatusForStudentList(Organization organization, AccountStatus accountStatus) {
return streamAllByOrganizationAndStatusForStudentList0(organization, accountStatus)
.map(o -> new BillingTargetAndStudent((BillingTarget) o[0], (Student) o[1]));
}
#Query("select bt, s from Student s join fetch s.user u join fetch u.attributes, BillingTarget bt join fetch bt.account a where s.id = bt.targetID and bt.account.status = :accountStatus and bt.account.organization = :organization")
Stream<Object[]> streamAllByOrganizationAndStatusForStudentList0(Organization organization, AccountStatus accountStatus);
I can reduce the query slightly by putting in one #EntityGraph
#EntityGraph("Student.forStudentList")
#Query("select bt, s from Student s, BillingTarget bt left join fetch bt.billingContractTargets bct join fetch bt.account a where s.id = bt.targetID and bt.account.status = :accountStatus and bt.account.organization = :organization")
Stream<Object[]> streamAllByOrganizationAndStatusForStudentList0(Organization organization, AccountStatus accountStatus);
#NamedEntityGraph(
name = "Student.forStudentList",
attributeNodes = {
#NamedAttributeNode("schedules"),
#NamedAttributeNode(value = "user", subgraph = "user.attributes"),
},
subgraphs = {
#NamedSubgraph(name = "user.attributes",
attributeNodes = {#NamedAttributeNode("attributes")})
}
)
But I am limited to just one and it has to be the entity for the repository. I cannot say
#EntityGraph("BillingTarget.forStudentList")
#EntityGraph("Student.forStudentList")

How to create mapping of composed object with Hibernate when using a complex sqlquery?

I am trying to use the below query with Hibernate's session.createSQLQuery.
The Entity object corresponding to user has an attribute called address.
The address object is created out of 5 fields from table 'user'.
If I do not use an SQLQuery it gets filled auto-magically.
However without the SQLQuery I can't get all the info I would get from the desired joins shown below.
The user entity object also attributes like accessPlan which I am filling up using
.addEntity("accessPlan", AccessPlan.class)
Query:
SELECT
user.*,
ap.*,
country.*,
auth.*,
GROUP_CONCAT(coup.code SEPARATOR ' ') coupons
FROM
user
INNER JOIN access_plan ap ON (user.access_plan = ap.id)
INNER JOIN country ON (user.country=country.code)
LEFT JOIN user_auth auth ON (user.id = auth.userid)
LEFT JOIN (
SELECT
trans.user_id,coupon.code
FROM
payments_transaction AS trans
INNER JOIN payments_coupon coupon ON (trans.payments_coupon_id=coupon.id)
) coup ON (user.id=coup.user_id)
GROUP BY user.id;
What can be the easiest way to fill up the composed address object while using the SQLQuery?
OR
Is there a way to avoid using SQLQuery for a query like this?
Please check below example from the section 'Returning multiple entities'
String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
List loggedCats = sess.createSQLQuery(sql)
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class).list()
In your case, cat = user, mother = address... somewhat like that.
I do not have anything to try out at the moment but I guess this will help.

How to fetch the user if all subjects are passed by using hibernate criteria?

I am working on hibernate by using criteria api ,I have Student and Subjects two entities is there ,Student have one to many relationship with subjects ,in Subjects table I have one column as result ,Now I want to write the query if Student passed all subjects(based on the result column ) I want to fetch that user other wise I don't want to return any user.How to write Criteria query for this.
#Entity(name="student")
public class Student
{
#column(name="Id")
private int id;
#column(name="name")
private String name;
#OneToMany(mappedBy = "student", cascade = CascadeType.ALL)
private List<Subject> subject = new ArrayList<Subject>();
//setter getter methods
}
#Entity(name="subject")
public class Subject
{
#column(name="Id")
private int id;
#column(name="subject_name")
private String subjectName;
#manytoOne
#Joincolumn(name="student_id")
private Suduent suduent;
#column(name="result)
private String result;
//setter getter methods
}
please check below sample data
Student :
Id------Name
1-------Test
2------Test2
Subjects
Id ---- Subject_Name ------ Result------ StudnetId
1------Java------------------pass---------1
2-------.net----------------fail---------1
3-------Java---------------pass---------2
4--------.net------------pass ---------2
Any one help me.
Hi I will try to answer your query from what I undertood
1. Criteria can only select projections, or the root entity.
2. The below code snippet should work for you to retrieve students with result as "pass".(I assume you store this as value in result when student passes the subject)
Criteria criteria = session.createCriteria(Student.class, "student");
criteria.createAlias("student.subject", "subject ");
criteria.add(Restrictions.eq("subject.result", "pass");
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
HQL will be better and simpler for you, try the below HQL .. Again I am making assumption about 'pass' as result.
select distinct student from Student student
join student.subject subject
where subject.result = 'pass'
For Your requirement "if Student passed all subjects" then return the student id
I guess you are trying to pass only students who have passed in all the subjects.So the sql query will look something like this:
SQL Query:
select student_id
from subject a
where result="pass"
group by student_id
having count(subject_id) = (
select count(subject_id)
from subject
where student_id = a.student_id
group by student_id
)
In Hibernate Criteria you can't actually do having count(subject_id), and hence you will have to manually pass the no of subjects that all students must have passed.
Code :
DetachedCriteria dc = DetachedCriteria.forClass(Subject.class,"subQuery");
dc.createAlias("student", "student");
dc.setProjection(Projections.rowCount());
dc.add(Restrictions.eqProperty("student.id","outerQuery.student.id"));
Criteria query = session.createCriteria(Subject.class,"outerQuery");
query.createAlias("student", "student");
query.setProjection( Projections.projectionList()
.add(Projections.groupProperty("student.id"))
.add(Projections.count("id"))
);
query.add(Restrictions.eq("result","pass"));
// The total number of subjects has to be passed explicitly.
query.add(Subqueries.eq(new Long(2), dc));

How to retrieve a member object of a class using Hibernate?

Using following code I can successfully retrieve address fields of a user, to do that I need to define all its fields using Projection. Imagine address has 100 fields, in this case I have to define all of them.
I am wondering if I can return just address object of customer without defining all its fields in Proposition?
I know I can retrieve id of address and use that to retrieve its object, but I am wondering if there is ano other method rather than this or defining all its fields.
Hibernate
.....
Criteria cre = session.createCriteria(User.class, "user")
.createAlias("user.address", "addr");
cre.add(Restrictions.eq("user.id", ID));
ProjectionList pl = Projections.projectionList();
pl.add(Projections.property("addr.id").as("id"));
pl.add(Projections.property("addr.unit").as("unit"));
.......
cre.setProjection(pl);
Address address = (Address) cre.list().get(0);
I used the following as well but it runs into error (could not resolve property: addr of: com.myProject.User)
pl.add(Projections.property("addr").as("address"));
Java
#Entity
public Class User {
#Id
#GeneratedValue
private long id;
#OneToOne
private Address address;
...
}
Use JPQL/HQL:
select a from User u join u.address a where u.id = :userId
The Criteria API is more limited than JPQL, and can't select any other entity than the root entity. It shouldn't be used if the query doesn't have to be dynamically composed. Of course, if the association is bidirectional, you can simply use
select a from Address a where a.user.id = :userId
or its equivalent Criteria:
Criteria c = session.createCriteria(Address.class, "a");
c.createAlias("a.user", "u");
c.add(Restrictions.eq("u.id", userId));
If the result you pull in from a query will match the fields of a DAO you have defined. I would just type-cast the result from an hql or native SQL query.
Select *
From Address a
where a.id = :userid
Address addrObject = (Address) query.uniqueResult();
Do like this
Criteria criteria = session.createCriteria(User.class, "user")
.createAlias("user.address", "addr")
.add(Restrictions.eq("user.id", userId))
.setProjection(Projections.property("addr"));
Address address = (Address) criteria.list().get(0);
Couple of options:
use lazy="false" for Address object. If you have to use lazy=true for some reason, you can run this query in a separate session and override the lazy behavior in that session.
Use the database specific query to get a list of field names and then dynamically generate Projections by looping through the field names.
For example,
In mysql
SHOW COLUMNS FROM Address
In postgres
SELECT * FROM information_schema.columns
WHERE table_schema = your_schema
AND table_name = your_table
I hope this helps.

hibernate self referencing table get rows by fk

table Student
----------------
id | somecolumn with string| fk(which is self referencing ID of the same table)
how can i make hibernate query that will fetch all items where value of id will match value of fk.
here is what i have tried but it doesn't works (it returns only 1 result instead of result set)
List<Student> list = (List<Student>) sessionFactory
.getCurrentSession()
.createQuery("from Student p join p.studentFKs p2 where p2.id = :parentId")
.setParameter("parentId", parentId).list();
can someone help me solve the mistery? i know that it can be achieved with Hibernate criterias also.
UPDATE answer is to change query to(join was invalid.. ):
select p from Student p join p.student p2 where p2.id = :parentId
i use something like this and this is work
property of join inside entity Student :
#ManyToMany(cascade = CascadeType.REFRESH)
private Set<Student> testJoins = new HashSet<Student>();
HQL to get that set :
select a.testJoins from Student a where a.id = :parentId
maybe you can change your query from p2.id = :parentId to-->> p.id = :parentId

Categories

Resources