Why this HQL statement is like an inner join?
select
user.id,
user.allocationVersion,
user.tx.statusId,
user.userId,
user.nameFirst,
user.nameLast,
user.email1,
user.statusId,
user.tx.name,
user.note1,
user.note2
from
module.bb.jpa.User as user
where user.clientId = :clientId
order by user.id DESC
The TX class which is referenced in the User class can be null. Why do I get a result as if I did an inner join? I just get Users with a TX but I want all of them.
The HQL reference talks about this in section 14.4:
HQL supports two forms of association joining: implicit and explicit.
The queries shown in the previous section all use the explicit form,
that is, where the join keyword is explicitly used in the from clause.
This is the recommended form.
The implicit form does not use the join keyword. Instead, the
associations are "dereferenced" using dot-notation. implicit joins can
appear in any of the HQL clauses. implicit join result in inner joins
in the resulting SQL statement.
from Cat as cat where cat.mate.name like '%s%'
[highlighting by me].
What your HQL is basically equivalent to is:
select
user.id,
user.allocationVersion,
user.tx.statusId,
user.userId,
user.nameFirst,
user.nameLast,
user.email1,
user.statusId,
user.tx.name,
user.note1,
user.note2
from
module.bb.jpa.User as user
join module.bb.jpa.Tx as tx -- This is an abbreviated inner join
where user.clientId = :clientId
order by user.id DESC
To "correct" this behaviour you will have to explicitly specify a left outer join or left join for short.
Because you have referenced tx.name in user. It should not work if you access it in Java but in HQL to get the value for this column Hibernate make implicit join. To get all values you should do it explicitly and include outer join option.
Related
I’m to create query with ordering by field of related entity, like this:
SELECT p FROM Patient p ORDER BY p.doctor.name
And sql-query that Hibernate builds based on that of JPQL uses CROSS JOIN with condition (effectively, inner join):
select patient0_.id as id1_1_, patient0_.doctor_id as doctor_i3_1_, patient0_.name as name2_1_
from patient patient0_ cross join doctor doctor1_
where patient0_.doctor_id=doctor1_.id
order by doctor1_.name
As a side-effect, all patients with nulls in ‘doctor’ field are excluded from result set. Is there any option I can switch to hint Hibernate to use LEFT JOIN in such cases? Can’t such a behavior be considered a bug? From common sense’ point, just adding ordering shoud not affect result count.
Example is intentionally simplified. In real world it’s a dynamically built criteria-query with variable set of filters and sortings. So I can not work it around and use explicit LEFT JOIN in JPQL.
I reproduced behavior of simplified example in version 5.3.9.Final and in latest 5.4.15.Final.
Appreciate any help.
You should use explicit join instead of hibernate implicit join.
SELECT p FROM Patient p left join fetch p.doctor d ORDER BY d.name
If there is lazy relation and it is not wanted that doctor is loaded, fetch should not be used.
SELECT p FROM Patient p left join p.doctor d ORDER BY d.name
This is how the implicit join is defined for JPA, as an inner join. So if you want to use left join semantics, you will have to use a an explicit left join.
If you want something more dynamic, I can recommend you take a look at a query builder like Blaze-Persistence that has left join semantics for implicit joins.
Here is a Spring WebMvc example application that supports dynamic filtering and sorting for paginated datatables: https://github.com/Blazebit/blaze-persistence/tree/master/examples/spring-data-webmvc
If I use Hibernate Criteria API like:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root<OneEntity> entityOneRoot = criteriaQuery.from(OneEntity.class);
Root<TwoEntity> entityTwoRoot = criteriaQuery.from(TwoEntity.class);
criteriaQuery.multiselect(OneEntity, TwoEntity);
Do I need to use EQUAL-restriction (as ON-restriction in SQL) for equaling IDs between both tables (entities)? Because of Cartesian product of both tables?
criteriaQuery.where(criteriaBuilder.equal(OneEntity.get("fk_id"), TwoEntity.get("id")));
I mean... In SQL using join we need to use on-clausule like:
select * from table_1 t1, table_2 t2 where t1.t2_id=t2.t1_id;
But I can't find information about it in API Criteria.
From JPA 2.1 specification, chapter 4.4.5 Joins:
An inner join may be implicitly specified by the use of a cartesian
product in the FROM clause and a join condition in the WHERE
clause. In the absence of a join condition, this reduces to the
cartesian product.
The main use case for this generalized style of join is when a join
condition does not involve a foreign key relationship that is mapped
to an entity relationship.
Example:
SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize
In general, use of this style of inner join (also referred to as
theta-join) is less typical than explicitly defined joins over
relationships.
Since JPQL is works the same way as Criteria API then equal restriction is needed in your query.
I attach one image of my problem:
In Testing jFrame jTextField I will insert customer id then after pressing ok button query will select and collect information related to that customer.Then it will show in the jTableModel.
I attach my database image.
Error is "SQL code cannot be executed".
You can do like this (without Join):
SELECT papers.paper_list,papers_rate.monday,papers_rate.tuesday,
papers_rate.wednesday,papers_rate.thrsday,papers_rate.friday,
papers_rate.saturday,papers_rate.sunday,magzines.magzine_name,magzines_rate.rate
FROM papers,papers_rate,magzines,magzines_rate
WHERE example_table.customer_id = ? AND other conditions"
This syntax is, in effect, a simple INNER JOIN. Some databases treat it exactly the same as an explicit JOIN. The WHERE clause tells the database which fields to correlate, and it returns results as if the tables listed were combined into a single table based on the provided conditions.(http://www.techrepublic.com/article/sql-basics-query-multiple-tables/)
You need to join the tables properly.
Like this:
SELECT
paper_list,monday,tuesday,wednesday,thrsday,friday,saturday,sunday,magzine_name,rate
FROM papers
LEFT JOIN papers_rate
ON papers_rate.paperId = papers.id
LEFT JOIN magzines
ON magzines.paperId = papers.id
LEFT JOIN magzines_rate
ON magzines_rate.magazineId = magzines.id
WHERE customer_id = ?"
If you do an inner join, all your results will vanish if you don't have a magazine_rate for example...
And check your spelling.
You're writing thrsday instead of thursday and magzine instead of magazine...
PS: And where does customer_id come from ?
Use joins to select multiple column from multiple tables. Refer this to get an understanding about the join and for join examples.
Note: There should be a common field between two tables to perform join operation
If the tables are related you must use JOIN: let's see an example (I don't know your tables fields, so I'll invent a custom example). Think about person and pet tables; the person tables could contain these fields:
Person (personID, first_name, last_name, age)
the pet table could contain these other fields:
Pet (petID, name, age, personID)
The personID field in the pet table identifies the owner of the pet. It is a simple 1:N relation. To select some values from these two tables you must do something like:
SELECT Person.first_name, Person.last_name, Pet.name
FROM Person INNER JOIN Pet ON
Person.personID = Pet.personID
WHERE Person.age > 30
This is just an example, clearly. And the INNER JOIN is just a join type (there are several join methods). Here you can find some documentation concerning these issues.
You need to either use a Join clause (... FROM papers JOIN papers_rate ON papers.[id_column] = papers_rate.[foreign_key]) or use an equi-join (replace JOIN...ON clause with a condition in the WHERE clause) (... FROM papers,papers_rate WHERE papers.[id] == papers_rate.[foreign_key])
Could you please post the schema of your tables?
to select an overview from a database I have to use a statement like this:
select a1.begin, a1.end, b1.name, c1.name, d1.name, e1.name, f1.name, ...
from a2, b1, b2, c1, c2, a1
left outer join (d1 join d2 on d2.id = d1.parent and d1.user = ?) on
d1.deleted = 0 and d1.parent = a1.d1_id
left outer join (e1 join e2 on e2.id = e1.parent and e1.user = ?) on
e1.deleted = 0 and e1.parent = a1.e1_id
left outer join (f1 join f2 on f2.id = f1.parent and f1.user = ?) on
f1.deleted = 0 and f1.parent = a1.f1_id
where .... a lot more stuff...
The statement works like a charm and the database has no problem to process it really fast. Believe me, there's definitely no other way to get the required data.
Until now I was pretty proud to say, that I don't have a single word of pure EJB-QL or even SQL in our java project. But now I'm not sure if there is any way to build such a statement by using the CriteriaBuilder. I have absolutely no idea how to create an outer join with more than the single criteria or even with a nested inner join.
Any hints greatly appreciated.
Thanks
Hennes
It's hard to give specific help without knowing the object model, but I believe you want to use the join method and specify the join type. Using it you can nest joins that will use the relationship defined on the specified attribute mapping. Explain action of the criteria API can be found here:
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Criteria#Join
Eclipselink also supports the 'on' clause in JPQL and criteria queries through feature https://bugs.eclipse.org/bugs/show_bug.cgi?id=367452
first join:
criteria=session.createCriteria(mappingClass.class).createAlias("propertyName","firstAliasName");
second join:
criteria.createAlias("firstAliasName.propertyName","secondAliasName");
and so on.
That will do OFC if you are joining by mapped relations. If not than read this:Criteria API
. The simplest way to do such think it would by by HPQL or JPQL, however you will probably wont get mapped enities as result, only ResultSet with columns (but you won't get it anyway I think)
How can provide OR clause in LEFT_JOIN in hibernate criteria.
Criteria mainCrit=hibernateSession.createCriteria("Main.class");
Criteria aPropertyCrit=mainCrit.createCrieria("child",CriteriaSpecification.LEFT_JOIN);
It generates sql as
select this_.Id,this_childId....
from main as this_
left join child as child1_ on child1_ .id=this_.childId
where.....
And I need to generate the sql as
select this_.Id,this_childId....
from main as this_
left join child as child1_ on child1_.id=this_.childId or child_.ParentId=this_.childId
where.....
How do I provide OR clause in LEFT_JOIN in above criteria.
The extending of the JOIN ... ON part, could be done, even with Criteria API. But only to be more restrictive, i.e. adding the AND part.
Take a look on the overloads of the createCriteria method, mostly the last parameter withClause:
Criteria createCriteria(String associationPath,
String alias,
JoinType joinType,
Criterion withClause)
throws HibernateException
Create a new Criteria, "rooted" at the associated entity, assigning the given alias and using the specified join type.
Parameters:
associationPath - A dot-seperated property path
alias - The alias to assign to the joined association (for later reference).
joinType - The type of join to use.
withClause - The criteria to be added to the join condition (ON clause)
In fact, any other approach (e.g. adding the OR), is breaking the mapping principal, introducing the ability to have the cross join at the end. see Hibernate criteria: Joining table without a mapped association