JPA: Aggregate entities in select query, with optional associations - entity-framework

given the following JPA entities:
A, with fields id, name
B, with fields id, name and 1-1 association a to A (one instance of B always exists for any instance of A)
C, with fields id, name and 1-1 association a to A (but one instance of C does not always exists for any instance of A)
I would like to have in a single query the id's and names of the 3 associated entities for all instances of type A, like:
select a.id, a.name, b.id, b.name, c.id, c.name from A a, B b, C c
where b.a=a and c.a=a
Since associations can't be bidirectional, we can't use JOINs from A to B and C, so we need to select from all the three entities (left outer JOIN could help, otherwise).
This is working well when all the 3 instances exists for a given instance of type A, but when there is no C instance for a given A, the query returns nothing.
Is there any way to configure the query so that it allows optional entities in the select clause? Or, is there any different way to define the query to return the requested values?
TIA.
Daniele

Related

Left Join an Element collection using JPQL

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.

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

Is JPA subquery in FROM clause possible?

I'm having a little problem with JPA. Consider this scenario:
Table A (id_a) | Table B (id_b, id_a)
What I need is a query like this:
Select a.*, c.quantity from A as a, (Select Count(*) as quantity
from B as b where b.id_a = a.id_a) as c;
The thing is that I want to use a jpa query and not a native query, something like this:
Select a, c FROM A a, (Select Count(b) FROM B b where a.idA = b.a.idA) c;
So then I could iterate from the result (a list of Object[] with a and c in each node) and then assign a.quantity = c;
I repeat, I don't want to use native query, but I found no other way than use redundant data, and add another column to A called Quantity and every time I insert and delete from B, update this column in A.
Please help, I read somewhere that JPA doesn't accept subqueries in Form clause, so, what can I do ?
Thanks a lot !
JPA does not support sub-selects in the FROM clause but EclipseLink 2.4 current milestones builds does have this support.
See,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause
You can probably rewrite the query with just normal joins though.
Maybe,
Select a, size(a.bs) from A a
or
Select a, count(b) from A a join a.bs b group by a

Issue with the count in PostgreSQL

I want the count of the one column and I have 5 columns in FROM clause but it is giving wrong count as I have included all my columns that are in the from clause. I don't want that particular column in the GROUP BY clause.
If I remove that column from GROUP BY clause it throws the following error:
ERROR: column "pt.name" must appear in the GROUP BY clause or be used
in an aggregate function LINE 1: SELECT distinct on (pu.id) pu.id,
pt.name as package_name, c...
E.g.:
SELECT DISTINCT ON (a) a,b,c,count(d),e
FROM table GROUP BY a,b,c,d,e ORDER BY a
From this I want to remove e from the GROUP BY.
How can I remove that column from GROUP BY so that I can get correct count?
Updated after rereading the question.
You are mixing GROUP BY and DISTINCT ON. What you want (how I understand it) can be done with a window function combined with a DISTINCT ON:
SELECT DISTINCT ON (a)
a, b, c
, count(d) OVER (PARTITION BY a, b, c) AS d_ct
, e
FROM tbl
ORDER BY a, d_ct DESC;
Window functions require PostgreSQL 8.4 ore later.
What happens here?
Count in d_ct how many identical sets of (a,b,c) there are in the table with non-null values for d.
Pick exactly one row per a. If you don't ORDER BY more than just a, a random row will be picked.
In my example I ORDER BY d_ct DESC in addition, so a pseudo-random row out of the set with the highest d_ct will be picked.
Another, slightly different interpretation of what you might need, with GROUP BY:
SELECT DISTINCT ON (a)
a, b, c
, count(d) AS d_ct
, min(e) AS min_e -- aggregate e in some way
FROM t
GROUP BY a, b, c
ORDER BY a, d_ct DESC;
GROUP BY is applied before DISTINCT ON, so the result is very similar to the one above, only the value for e / min_e is different.

Can I get Entity Framework to create code for my many-to-many relationship tables?

Say I have the MSSQL tables A, AB and B, where AB is a simple ManyToMany mapping table containing two columns: Primary key for A and Primary key for B. Entity Framework does not generate a class for AB, only a collection of B in A and of A in B. Sometimes I want to list the contents of AB as is.
Is there any way I can get EF to generate code for the AB ManyToMany-table?
PS I'm using Rob Halletts Mocking Context Object Generator for code generation. Don't know if this is relevant.
No, you can't. The join table is never represented as an entity in your model. But you can list the content of the AB join table also without that entity:
var joinTableList = (from a in context.As
from b in a.Bs
select new
{
AId = a.Id,
BId = b.Id
})
.ToList();
You get a list of of anonymous objects. Every object has the AId and BId as properties. This LINQ query is translated into a very simple SQL query over table AB without any joins:
SELECT
[Extent1].[AId] AS [AId],
[Extent1].[BId] AS [BId]
FROM [dbo].[ABs] AS [Extent1]