Hibernate query for two tables - java

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

Related

Join cartesian product

Context
I send some files to some enterprises every week. I need to restitute for each week and each enterprise whether the file is sent or not.
Tables
ent (enterprise)
wek (week)
fil (file : references wek and ent)
Solution with pure SQL
Make a cartesian product between ent and wek then left outer join fil. This works :
select * from
(
select * from wek, ent e
) as t1
left join fil f
on f.ent_id = t1.ent_id
and f.wek_id = t1.wek_id
Problem :
How to translate this into JPA (in the CriteriaBuilder way)?
For example, if I try :
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ResultClass> query = cb.createQuery(ResultClass.class);
Root<Week> week = query.from(Week.class);
Root<Enterprise> query.from(Enterprise.class);
Expression<???> cartesianProduct = ??? //How?
cartesianProduct.leftJoin(???_.file);
query.where(
cb.equal(file.get(File_.wek_id), week.get(Week.week_id));
)
Using 2 "from" clauses gives me the cartesian product but how do I left join this result?
Unstatisfaying solution :
Create a view :
CREATE VIEW view_ent_wek AS
SELECT ent_id as ent_id, wek_id as wek_id, ent_id || '-' || ent_id as id
FROM ent, wek;
Map it to an entity :
#Entity
#Table(name = "view_ent_wek")
public class WeekEnterprise {
#Id
#Column(name = "id")
private String id;
#ManyToOne
#JoinColumn(name = "ent_id")
private Enterprise enterprise;
#ManyToOne
#JoinColumn(name = "wek_id")
private Week week;
[...]
Then I can use it in a query :
Root<WeekEnterprise> weekEnterprise = query.from(WeekEnterprise.class);
weekEnterprise.join(...)
I don't like this solution because it makes me create a view that is obviously not necessary. Any idea?
I don't see the point of doing the reporting-style SQL query with JPA, let alone with Criteria Query.
Of course, JPA (and its implementations) do support tuple queries (as opposed to entity queries, see also: Hibernate tuple criteria queries), but tuple queries is not what JPA is good at. Imagine you want to change that report and add more calculations. Wouldn't it be much easier to do that with SQL?
Using JPA for mapping to Java objects and for transaction modelling still makes sense, and thus, your SQL view solution is already quite good, or if you prefer not to store the SQL in a view, use JPA's native query API:
List<Object[]> list = em.createNativeQuery(sql).getResultList();
Or:
List<WeekEnterprise> list = em.createNativeQuery(sql, WeekEnterprise.class)
.getResultList();
I have some ideas:
With 2 JPA queries. First: fetch the cartesian product of wek and enterprises. Second: take an inner join between wek, enterprises and files. Uses a map (wek_id+ent_id => Tuple(Wek, Ent, File)) to quickly identify where to put the file.
Write plain SQL queries and execute them with the JPA API.
(Didn't think much about this one) Create a back reference from Wek and Ent to File (lazy loaded) and then you should be able to continue your first idea.
Don't know much about JPA, but about Postgres. And I would suggest this superior query:
SELECT *
FROM wek CROSS JOIN ent
LEFT JOIN fil USING (ent_id, wek_id);
You don't need the subselect.
The only difference in the result (besides being shorter and faster): You get the columns ent_id and wek_id once in the output (which might solve a problem with duplicated column names).
Should be easy to translate to JPA now.

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"

HQL query join tables

I am using hibernate to connect to my database for a project.
I would like to have a query that gets the products out of my database with the discription and name in a certain language. The parameter I have is the short name for the language, so first I would have to get the id of the language and then get the text in the required languages.
I have tried the following hql query, without success.
from Products as p
where p.productlanguages.languages.shortname like 'eng'
This is an image of the part of the database where the data should come from:
I have got the desired result with an sql query, but I can't seem to get it to work in hibernate. But I would prefer to do this in hql.
SELECT * FROM products p
INNER JOIN productlanguage pl ON pl.Products_id = p.id
WHERE pl.Languages_id =
(
SELECT id FROM languages
WHERE Shortname = 'eng'
);
Could anyone tell me how to build this hql query?
Thank you.
Try below:
from Products p INNER JOIN p.productlanguages pl
where pl.languages.shortname ='eng'
I am assuming that you have mapped Product-Productlanguages relationship as OneToMany and Productlanguages-Langages relationship as ManyToOne as depicted in your E-R diagram.
EDIT: There seems to be a typo in Productlanguage mapping at line public Languages getLanguages() {barcode, remove the barcode in the end.
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="Languages_id", nullable=false, insertable=false, updatable=false)
public Languages getLanguages() {barcode
return this.languages;
}

HQL query trouble

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 )

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