HQL query trouble - java

I hava a java app, with 2 objects: User.java and Review.java.
Each User can have many Reviews.
Review object has a User object on it (eg: review.getUser())
I need an hql query that will get all Users that have no Reviews. How do I do this?

Try
from User u where u.reviews is empty
assuming your User class has a collection of reviews, of course...

from User u where not exists (from Review r where r.user = u)

I do not know your tables and the columns in these tables, but anyway you should have a query like the following:
select *
from User
where not exists (select Review where Review.userId = User.id )

Related

I can't use any ID in my code

I was always taught to use IDs in my code to refer to records into the database.
But let's take the case we have same roles in the table Role. Now I want to query only the records related to the role Player:
ID ROLE
1 Admin
2 Organizer
3 Player
I don't know in my code the ID of Player, but I want to retrieve all the players, so with Hibernate I wrote:
String queryString = "from User u where u.role.role = ?";
Query queryObject = getSession().createQuery(queryString);
queryObject.setParameter(0, "player");
return queryObject.list();
As you can see I wrote "player" in the code. I think this is not the best way and I should use an ID instead. But I don't know the ID and it may change depending on the server on which I run the application. A second problem with my solution is that "player" can be capitalized into the database and this may be changed over time.
So, what should be the solution to all these problems? Is there any way to use the ID instead? Or any other way to improve this code?
In this case it seems that role should be an enum and your query would look something like:
queryObject.setParameter(0, Role.PLAYER);
Also, you might take a look at the criteria API which will help you create more type-safe queries that are more robust vs. refactoring.
You should create a enum class like this.
public enum Role {
Admin(1),
Organizer(2),
Player(3);
}
And change your code to
String queryString = "from User u where u.id= ?";
Query queryObject = getSession().createQuery(queryString);
queryObject .setParameter(0, Role.PLAYER);
return queryObject.list();
You can do using create a mapping table like ,
UserRoleMapping
ID - Incremental,
UserId - Refers to user table,
RoleId - Refers to role table
As one user can have more than one role so it will satisfy that thing too.
to Get the roles using query
select role.id from userrolemapping urm innerjoin on user u.id = urm.id where u.id = ?
using IDs or string/vachar etc. lookup is all dependent on the data that you have in the database. Some organization keep the id static and some keep the name/description static. So, make sure you have good understanding of your DB data and what will stay static . However, if the role is static you can use HQL ignore case like the example I provided for you below (I'm not adding information about the ID static path because others have already provided information about it for and don't want to duplicate it ).
--note you can take the percentages out if you only want "player"
String queryString = "from User u where lower( u.role.role ) like lower('%"+ ? +"%')";
Query queryObject = getSession().createQuery(queryString);
queryObject.setParameter(0, "player");
return queryObject.list();

Hibernate query for two tables

I am new to hibernate so I am pretty sure that some of you would be amused by this question. It has been driving me crazy. This is a hibernate query question.
I have two tables, Assuming one is outlet and one is flyers
outlet - outlet name,outlet address, merchantName
flyers - flyerId, flyerName, merchantName
so flyers belong to a merchant and a merchant has many outlets etc,
using hibernate, to get a simple query like to get the different outlets from the outlet table using the merchantName, I use the code:
public List<Outlet> getDealOutlet(#PathParam("merchant") String merchant) {
some code here....
outletsList = session.createQuery("from Outlet as outlet where outlet.merchantName = :merchant").setString( "merchant", merchant ).list();
some code here
}
And that works.
My question is how do I return the lists of outlets for a particular flyerId.
Any help is appreciated thanks
Is the question "How can I return the list of outlets for the merchant associated with a particular flyerId?"
If so, do you have a table merchants that's mapped to a class Merchant? That's the path to go down; Hibernate can easily let you query across joins, but if Hibernate doesn't know about the join because all you've got is a magic String called merchantName that you know happens to be the same in the two tables, then Hibernate can't help you out.
(Though of course you could run two queries, but I doubt that's what you're looking for.)
It depends on your mappings, if there is an Merchant entity, and both other entities have an association to it, it can be written as:
select o
from Outlet o
join o.merchant m
join m.flyers f
where f.id = :flyersId
Other wise you can do something like you do in SQL:
select o
from Outlet o, Flyers f
where o.merchant = f.merchant and f.id = :flyersId

avoiding multiple selects when using kew word "new" in hql

I have the following code in java.
List<UserHelper> users=List<UserHelper>)session.getNamedQuery("PkUser.loadHelperUsers").list();,
I think it does not matter what the "UserHelper" class is that's why I do not write it, not to overload my question. This is my namedQuery mentioned above.
#NamedQuery(name = "PkUser.loadHelperUsers", query = "SELECT new ge.tec.pto.ext.helpers.UserHelper(u) from PkUser u order by u.pkUserId desc"),
The problem is that the hql selects too many rows, I think the same number of rows that is in database in pk_user table.If anyone knows how to fix this please inform me. It will be very nice if the solution will not require to alter my "NamedQuery", It will be graet if I will have to change only my Query creation, But any solutions will be helpful, Thank you
Multiple selects when using Key word “`new`” in `hql`
There is no problem with your code and with NEW keyword .
Your query will return all the Rows in the UserHelper related Table
You should use a WHERE clause to get the required rows .
EX :
query = "SELECT new ge.tec.pto.ext.helpers.UserHelper(u) from PkUser u where username=:passedparamer order by u.pkUserId desc"

Select records which doesn't have specific records in joined table

Hi I'm trying to select records from one table which doesn't have records in connected many-to-many table with specific values.
I will explain on sample tables:
documentation:
id_documentation
irrelevant_data
user:
id_user
irrelevant_data
documentation_user:
id_documentation
id_user
role
What I want to achieve is to select every single documentation which doesn't have user in specific role. Any ideas?
The main problem is that I'm using java's CriteriaBuilder to create query so using subqueries is impossible (I think).
You can add restrictions on your left join using: createAlias(java.lang.String, java.lang.String, int, org.hibernate.criterion.Criterion) method, see API.
Check this answer for an example on how to use the left join with a criteria.
Main problem does not exist - Criteria API do have SubQuery. Query itself selects instances of User and uses not in construct to limit results based to subquery. Subquery selects all users that are connected to document with specific role via DocumentationUser.
Try something like this (code not tested):
CriteriaQuery<Documentation> cq = cb.createQuery(Documentation.class);
Root<Documentation> u = cq.from(Documentation.class);
Subquery<Integer> sq = cq.subquery(Integer.class);
Root<User> su = sq.from(User.class);
sq.select(su.get("id_user"));
Join<User, DocumentationUser> du = su.join("documentationUserCollection");
sq.where(cb.equals(du.get("role"), "mySpecificRole"));
cq.where(cb.not(cb.in(u.get("id_user")).value(sq)));
See also this useful answer on SO.

How to convert nested SQL to HQL

I am new to the Hibernate and HQL. I want to write an update query in HQL, whose SQL equivalent is as follows:
update patient set
`last_name` = "new_last",
`first_name` = "new_first"
where id = (select doctor_id from doctor
where clinic_id = 22 and city = 'abc_city');
doctor_id is PK for doctor and is FK and PK in patient. There is one-to-one mapping.
The corresponding Java classes are Patient (with fields lastName, firstName, doctorId) and Doctor (with fields doctorId).
Can anyone please tell what will be the HQL equivalent of the above SQL query?
Thanks a lot.
String update = "update Patient p set p.last_name = :new_last, p.first_name = :new_first where p.id = some (select doctor.id from Doctor doctor where doctor.clinic_id = 22 and city = 'abc_city')";
You can work out how to phrase hql queries if you check the specification. You can find a section about subqueries there.
I don't think you need HQL (I know, you ask that explicitly, but since you say you're new to Hibernate, let me offer a Hibernate-style alternative). I am not a favor of HQL, because you are still dealing with strings, which can become hard to maintain, just like SQL, and you loose type safety.
Instead, use Hibernate criteria queries and methods to query your data. Depending on your class mapping, you could do something like this:
List patients = session.CreateCriteria(typeof(Patient.class))
.createAlias("doctor", "dr")
.add(Restrictions.Eq("dr.clinic_id", 22))
.add(Restrictions.Eq("dr.city", "abc_city"))
.list();
// go through the patients and set the properties something like this:
for(Patient p : patients)
{
p.lastName = "new lastname";
p.firstName = "new firstname";
}
Some people argue that using CreateCriteria is difficult. It takes a little getting used to, true, but it has the advantage of type safety and complexities can easily be hidden behind generic classes. Google for "Hibernate java GetByProperty" and you see what I mean.
update Patient set last_name = :new_last , first_name = :new_first where patient.id = some(select doctor_id from Doctor as doctor where clinic_id = 22 and city = abc_city)
There is a significant difference between executing update with select and actually fetching the records to the client, updating them and posting them back:
UPDATE x SET a=:a WHERE b in (SELECT ...)
works in the database, no data is transferred to the client.
list=CreateCriteria().add(Restriction).list();
brings all the records to be updated to the client, updates them, then posts them back to the database, probably with one UPDATE per record.
Using UPDATE is much, much faster than using criteria (think thousands of times).
Since the question title can be interpreted generally as "How to use nested selects in hibernate", and the HQL syntax restricts nested selects only to be in the select- and the where-clause, I would like to add here the possibility to use native SQL as well. In Oracle - for instance - you may also use a nested select in the from-clause.
Following query with two nested inner selects cannot be expressed by HQL:
select ext, count(ext)
from (
select substr(s, nullif( instr(s,'.', -1) +1, 1) ) as ext
from (
select b.FILE_NAME as s from ATTACHMENT_B b
union select att.FILE_NAME as s from ATTACHEMENT_FOR_MAIL att
)
)
GROUP BY ext
order by ext;
(which counts, BTW, the occurences of each distinct file name extension in two different tables).
You can use such an sql string as native sql like this:
#Autowired
private SessionFactory sessionFactory;
String sql = ...
SQLQuery qry = sessionFactory.getCurrentSession().createSQLQuery(sql);
// provide an appropriate ResultTransformer
return qry.list();

Categories