JPA 2.1 Left join on sub collection with filter of sub collection via 'on' clause - eclipselink

Given the following JPQL query:
Select p, child, subChild
from Entity parent p
left join Child parent.children child
left join SubChid child.subChildren subChild on subChild.field = 'value'
I expect to have the parent entity with only child which have subChild with field = 'value' and I also expect to have the child.subChildren filtered to only return the one matching the 'on' clause. I am wondering if this is allowed by JPA 2.1. This seems to be but I tried with eclipselink 2.5.3 and it doesn't work as expected.
The SQL query generated is correct. It returns only the expected rows but the parent entity is not filtered and is returned with the complete object graph which I don't understand.
Can someone give me some inside on how to solve that issue?

Related

How to write a Hibernate query using the WITH clause to customize the ON clause

I am using the following HQL query:
feeds = (List<Album>) session.createQuery(
"select distinct album from Album as album "
+ "left join album.postImageses as pi with pi.isAlbumCover=:isCover "
+ "where album.atom.id=:aid ")
.setParameter("isCover", "Yes")
.setParameter("aid", id)
.list();
This query is working properly.
But problem is that I want to fetch only Images frompostImageses whose isAlbumCover value is 'Yes'
but above query is fetching all images(images are album cover or not).
So how can I fetch only images(not other) with isAlbumCover='Yes'.
How to resolve this.
Hibernate cannot give you partial one-to-many results. You always get all children to ensure consistency.
You need to turn your query up-side down:
select ps
from PostImage ps
inner join fetch ps.album albm
inner join fetch albm.atom atm
where ps.isAlbumCover = :isCover and atm.id = :aid
This query assumes you have a bi-directional association between an Album and a PostImage, so a PostImage has a #ManyToOne album reference too.
For a proof this is not possible, this is what the Hibernate documentation says:
A fetch join does not usually need to assign an alias because the
associated objects should not be used in the where clause (or any
other clause).
So the fetch is not affected by where clauses. In your case the with clause can at most filter the root entity (Album), but all associated collections (postImageses) will be subject to the fetching policy.
Because you don't explicitly use a fetch directive, it means the query will use the mapping fetch policy. If the one-to-many association is LAZY, it won;t be initialized in this query. Once you access it, Hibernate will issue a new query to initialize it, that's why the with clause doesn't filter the children collection.

SQL Conditional joins, data inheritance

I need to implement a data inheritance logic, based on a dynamic tree, with a fixed depth of 3.
Output 1
--Output 1.1
--Output 1.2
----Ouptut 1.2.1
----Output 1.2.2
--Output 1.3
Ouput 2
-- Output 2.1
-- Output 2.2
-- etc.
So I have an object defined as followed:
Object
-id
-createdAt
And the data attached to the object
ObjectData
-owner_id (fk to the object)
-output_id (fk to the output)
-name (this is the real data)
What I am trying to do is retrieve a list of Object, inner join the ObjectData base on owner_id/ouput_id, but if no ObjectData with given output_id exists, join the ObjectData of parent output.
At the moment, with my basic SQL query, if the object_data has no entry with a given output, it is not returned, which is how works INNER JOIN.
SELECT c.*, d.name FROM object c
INNER JOIN object_data d ON c.id = d.owner_id AND d.ouput_id = ?
What I am trying to achieve is to avoid having to create a new object_data entry when data is fully inherited, to optimize storage size, and to avoid huge inserts when adding a new output.
I must also be able to order the query on a object_data field.
Thank you !
EDIT:
Thanks to Gordon Linoff I think that coalesce is a solution for my problem, but according to mysql doc, coalesce will return first non null.
In my case, if the row exists, I want to return its value wether it is null or not.
I think I understand what you want. The following SQL joins in both the object data and the parent's object data, and then chooses between them in the select statement:
select o.*, coalesce(od.name, od_parent.name)
from object o left outer join
objectdata od_o
on od_o.id = o.id left outer join
objectdata od_parent
on od_parent.id = o.parent_id
This may seem like unnecessary effort on the part of the database engine. But most engines are highly optimized for joining tables together, so performance probably is not an issue -- especially if you have the right indexes on the tables.

How to select one table using NHibernate CreateCriteria

How can I create the following SQL statement in Nhibernate using CreateCriteria:
SELECT distinct top 20 a.* from ActivityLog a
left join WallPost w on a.ActivityLogId = w.ActivityLogId left join ItemStatus i on i.StatusId = w.ItemStatus
I always tend to get all columns from all tables returned in the sql statement producing duplicates even though I map it to the ActivityLog table. I am also doing paging as the code below shows:
ICriteria crit = nhelper.NHibernateSession.CreateCriteria(typeof(Model.ActivityLog), "a").CreateAlias("a.WallPosts", "w",CriteriaSpecification.LeftJoin)
.CreateAlias("w.ItemStatus", "i", CriteriaSpecification.LeftJoin)
.SetMaxResults(pageSize).SetFirstResult(startRow).AddOrder(Order.Desc("a.Date"));
Thanks
H
Sounds like you have set lazy loading to false in your mapping files meaning that all the associations and child collections are being loaded up too. Can you verify that?
You ask "How to select one table using NHibernate CreateQuery" (HQL). In that case you can choose what to fetch using select.
In your text you're using criteria. AFAIK, you cannot directly control what columns you want to read. However, if you create a DetachedCriteria for the join, this won't be fetched.

SQLite3 and "cascade" SELECTion

I have a parent table and a child table related to the parent table by some REFERENCE.
Suppose I exec a SELECT statement on the child and that it returns the at least one result. Can I arrange for my search to automatically yield all the content of all related parents with this child too?
Or must I always take the reference from the child and put this in a second SELECT statement and exec this myself?
You can use subqueries:
SELECT *
FROM Parent
WHERE Parent.Id IN (SELECT ParentId
FROM Child
WHERE Whatever_was_your_original_query)
Or a good old join:
SELECT Parent.*
FROM Parent INNER JOIN Child ON Parent.Id = Child.ParentId
WHERE Whatever_you_want_to_query
This is the very basic purpose of SQL. You will JOIN the two tables together to create one set of result rows with some or all columns from BOTH tables included.
For more info, see this page.

NHibernate : Count childrens' children

I have an entity type A. Which has many B's. The B entity has many C's.
I need to count how many C's does an A entity have. How can this be done using NHibernate Criteria API?
Using LINQ to NHibernate I was unable to get results since it throws an exception (see this question)
This query becomes simpler if you use C as starting point of the query, rather than A. This is possible since you use bidirectional mappings, according to the mapping you show in your other question.
The way I would do this is to find all Cs which have a B which has a given A, and then count the found Cs.
To Add a constraint on the B of a C, you can add an alias and then add restrictions to that alias. To perform a count query rather than returning the found Cs you can use the SetProjection method and specify a Count projection. Since the count projection returns a single integer value, use UniqueResult to get the count.
using (ISession session = SessionFactorySingleton.OpenSession())
{
int numberOfCsForA1 = session.CreateCriteria<C>()
.SetProjection(Projections.Count("Id"))
.CreateAlias("B", "b")
.Add(Restrictions.Eq("b.A.Id", a1.Id))
.UniqueResult<int>();
// ...
}
The SQL generated by this query looks like this:
SELECT count(this_.Id) as y0_
FROM [C] this_
inner join [B] b1_
on this_.IdB=b1_.Id
WHERE b1_.IdA = #p0;#p0 = 12
As you can see, it is a two-way join, since NHibernate is smart enough to realize that it does not need to join with the A table to get the id of a Bs A. Instead it simply looks at the IdA value of the B.