Left Join an Element collection using JPQL - jpa

Suppose I have this classes, notice that entities are not related in anyway.
#Entity
class Laptop {
#Id
String userId;
#Column
String name;
...
}
#Entity
class Foo {
...
#Column
#ElementCollection
List<String> idsPointingToAnEntity;
...
}
Given that I have this Foo class which has an attribute of idsPointingToAnEntity, I could store there a list of Laptop ids or any ids of String. Let's say Foo has idsPointingToAnEntity=[1,2,3], this [1,2,3] has an equivalent Laptop entry in the database.
How can I left join/ join them with ordering in JPQL such given that the result is a list of Foo sorted by Laptop names.
In theory I think it is something like this.
Select f From Foo f LEFT JOIN Laptop l ON l.id IN f.idsPoitingToAnEntity ORDER by l.name
But this is having an error for me since f.idsPoitingToAnEntity is a Join table.
Note: idsPointingToAnEntity can also be another entity making List<Laptop> is not an option

If you are using JPA 2.1 or higher you use JOIN ON in JPQL on unrelated entities. Join the IDs table first, like this:
select f from Foo f
join f.idsPointingToAnEntity id
join Laptop l ON id=l.id
join AnotherEntity a ON id=a.id

You can use no Joins to obtain this result:
SELECT l FROM Laptop l, Foo f
WHERE l.id IN f.idsPointingToAnEntity ORDER BY l.name
Or use CROSS JOIN, a special kind of join that don't require any matching conditions:
SELECT l FROM Laptop l
CROSS JOIN Foo f
WHERE l.id IN f.idsPointingToAnEntity ORDER BY l.name
PS: the problem of using cross join in this scenario, is that it generates the Cartesian Product, not all the rows from left side.

Short answer here is simply don't do that. It is misusing the specific feature and likely to lead to troubles as your list grows. You have no good justification for doing this. If you think the list is small then the database load is minimal and there is no reason to put references into an ElementCollection. If the list gets large you definitely don't want an ElementCollection.
Reference Difference between #OneToMany and #ElementCollection?. An ElementCollection is for creating a OneToMany between, in your case, Foo and idsPointingToAnEntity. It's definitely not meant to be used as a One-To-Many Relationship with Join Table.

Related

JPA when to use Path of entity type instead of Join?

An example in JPA spec:
CriteriaQuery<Customer> q = cb.createQuery(Customer.class);
Root<Customer> customer = q.from(Customer.class);
Join<Customer, Order> order = customer.join(Customer_.orders);
q.where(cb.equal(cb.treat(order.get(Order_.product), Book.class)
.get(Book_.name),
"Iliad"));
q.select(customer);
order.product is a path in the where clause. If it is not join, how to access
the name attribute of the product(Book)? Is it actually a table join when translated to SQL? If this is the case, what is the difference between path
and join in this example?
Order Product
---------- -------------
productId id name
Is it actually a table join when translated to SQL?
Yes, it is.
what is the difference between path and join in this example?
Let me explain using JPQL, it will be clearer. Your code is roughly equivalent to:
SELECT c FROM Customer c
JOIN c.orders o
WHERE o.product.name = 'Illiad'
Single-valued associations can be queried both by implicit joins (using path navigation) and explicit joins (using JOIN). It is important to remember that implicit joins are inner joins by default. The above query is therefore equivalent to:
SELECT c FROM Customer c
JOIN c.orders o
JOIN o.product p
WHERE p.name = 'Illiad'
This syntax is more verbose, but allows you to specify the join type, if need be.
Multi-valued associations behave a little differently. The following query:
SELECT c FROM Customer c
JOIN c.orders.product.name = 'Illiad'
will not compile. The shorthand syntax cannot be used here, as c.orders represents the collection as a whole and not its individual elements. To refer to individual elements, we need to dereference the collection, which makes the JOIN c.orders o syntax mandatory (the alias o now refers to individual elements inside c.orders)
On the other hand, no explicit joins are required when refering to the multi-valued association as a whole, e.g.:
SELECT c FROM Customer c
WHERE SIZE(c.orders) > 5
SELECT c.orders FROM Customer c

What's the difference between "JOIN FETCH" and "JOIN"?

Supposing I have a Person entity that has #OneToMany relationship with Phone entity. If I want to eagerly fetch Phone entities associated with a Person, I got 2 options:
SELECT p FROM Person p JOIN p.phones
or
SELECT p FROM person p JOIN FETCH p.phones
So what is the difference between them?
Remember that, in the end, JOIN FETCH is always a JOIN.
By default #OneToMany relationships are lazy loaded.
Using JOIN FETCH you load the related entities in advance.
You can find more info reading FETCH JOIN is still a JOIN by Piotr Nowicki

JPQL inner join and left join

I know what joins are and how to use them in plain SQL but i can't find any explanation of internet to query object with relations. I use entity,getList.size() to query objects that has oneToMany or ManyToMany associations with my entity. I'm wondering is there any way to query object with all his relations.
public Person
#OneToMany
List<Cat>
#ManyToMany
List<DormRoom>
what is do to get all object is;
Person p=PersonDAO.getWithId(1L);
p.getCats.size();
p.getsDormRooms.size();
Now i'm wondering the get fully evulated object with JPQL, CriteriaBuilder and maybe with QueryDSL.
It's called a fetch join:
select distinct p from Person p left join fetch p.cats left join fetch p.dormRooms
where p.id = :id
Beware though:
in Hibernate at least, that will only work if at most 1 of the collections is a bag (i.e. a list without any specified order column).
that will create a query returning the cartesian product of cats * dormRooms. So if a person has 100 cats and 100 dormRooms, 10,000 rows will be retrieved.

JPQL Left Join on clause

I have several entities and want to do a join like this:
SELECT g FROM Gift g
LEFT JOIN Worker w ON g.receiver = w.person
WHERE ....
AND w.company = :companyId
The problem is that there's no direct connection between g.receiver who is a Person and w.person. I don't want to inner join them either, because a receiver of a gift may not be a worker of a company.
I had the same problem, but i didn't find any solution in JPQL, it looks like if you don't have a mapped relation, you can't perform a left join.
I solved the problem with 2 query and a join implemented by code.
Another solution is a native query.

SQL Server 2008: many to many tables with relational tables ordering field + grouping

To understand what I need, here is the table's I'm using diagram: http://pascalc.nougen.com/stuffs/diagram.png
I need to get a project's properties + all it's relation, all listed based on the corresponding relational tables' OrderNumber column.
Let's say I need "Project Z", I want to get:
Project's BaseUrl, ... where ID = #ID
All testsuites associated to that project, listed by ProjectsToTestSuites.OrderNumber
All testcases associated to the matching testsuites, listed by TestSuitesToTestCases.OrderNumber
All testaction associated to the matching testcases, listed by TestCasesToTestActions.OrderNumber
So far, all my attempts are returning back results with mixed ordering. A testcase is mixed inside a testsuite it doesn't belong to and alike.
I try to avoid using cursors (loop each relation in specific order required), tried the use of UNION but couldn't get it to work either.
I wouldn't have troubles with cursor but if a solution exists withuout the need to use it, I prefer of course.
Thanks
If you want a flat result you could start with something like this (untested)
select
p.Id,
p.BaseUrl,
ts.*,
tc.*,
ta.*,
pts.OrderNumber as SuitesOrder,
tstc.OrderNumber as CasesOrder,
tcta.OrderNumber as ActionsOrder
from
Projects p
join
ProjectToTestSuites pts
on pts.Projects_Id = p.Id
join
TestSuites ts
on ts.Id = pts.TestSuites_Id
join
TestSuitesToTestCases tstc
on tstc.TestSuites_Id = ts.Id
join
TestCases tc
on tc.Id = tstc.TestCases_Id
join
TestCasesToTestActions tcta
on tcta.TestCases_Id = tc.Id
join
TestActions ta
on ta.Id = tcta.TestActions_Id
where
p.Id = #Id
order by
pts.OrderNumber,
tstc.OrderNumber,
tcta.OrderNumber