JOIN triangle relationship - entity-framework

The relationship:
Profil>Branch>City
Profil>Hotel>City
command:
from p in Profil.getData()
join b in Branch.getData() on p equals b
join h in Hotel.getData() on p equals h
join c in City.getData()
^how to reuse the equals join
Can I join City to Branch and Hotel table?
Can I just clone the c without City.getData()?

Sure, just do (following your pseudo code):
from p in Profil.getData()
join b in Branch.getData() on p equals b
join h in Hotel.getData() on p equals h
join c1 in City.getData() on b equals c1
join c2 in City.getData() on h equals c2
EF will translate this into two aliases for the City table. So you don't reuse or clone the cities, but in SQL that's not possible either. SQL server will be able to optimize it in the query's execution plan though.

Related

groupingBy a join in KTORM

I want to join a N x M relation, returning all N, and a count of how many M are there:
SELECT N.*, COUNT(M.id) FROM N LEFT JOIN M ON N.id = M.n_id GROUP BY N.id
but I don't see how. Joining and aggregation seem to exclude each other, or are not implemented, or not documented (or I didn't find it).

Can I mix LINQ and Fluent Syntax in EF Core?

I have the following query which works just fine (inasmuch as it generates the proper SQL command):
var sites = from sm in this.context.SiteMemberships
join s in this.context.Sites on sm.SiteUid equals s.SiteUid
join sd in this.context.SiteData on s.SiteUid equals sd.SiteUid
join p in this.context.Providers on s.ProviderUid equals p.ProviderUid
join r in this.context.Regions on p.RegionUid equals r.RegionUid
join o in this.context.Offices on s.OfficeUid equals o.OfficeUid
join u in this.context.Users on sm.UserUid equals u.UserUid
where
u.Email == userEmail ||
EF.Functions.Like(s.Classification, "117400-74%")
select new {
s.Field1,
sd.Field2,
p.Field3
};
As you can see, it's a complex query and trying to use the Fluent API is very cumbersome. However, I want the 'Where' clause to be programmable. Based on what features the current user has, they should be able to search on different criteria. A Level 1 support person can search only on an exact match of the Classification field, but a Level 2 support person can search on wildcards.
Is there any way to mix the syntax. What I want is something like this:
var (sites = from sm in this.context.SiteMemberships
join s in this.context.Sites on sm.SiteUid equals s.SiteUid
join sd in this.context.SiteData on s.SiteUid equals sd.SiteUid
join p in this.context.Providers on s.ProviderUid equals p.ProviderUid
join r in this.context.Regions on p.RegionUid equals r.RegionUid
join o in this.context.Offices on s.OfficeUid equals o.OfficeUid
join u in this.context.Users on sm.UserUid equals u.UserUid)
.Where(g => this.GetSearchCriteria(g))
.Select(g => g);
You need to add select new { s, sd, p, r, o, u } after your last join
var sites = (from sm in this.context.SiteMemberships
join s in this.context.Sites on sm.SiteUid equals s.SiteUid
join sd in this.context.SiteData on s.SiteUid equals sd.SiteUid
join p in this.context.Providers on s.ProviderUid equals p.ProviderUid
join r in this.context.Regions on p.RegionUid equals r.RegionUid
join o in this.context.Offices on s.OfficeUid equals o.OfficeUid
join u in this.context.Users on sm.UserUid equals u.UserUid
select new { s, sd, p, r, o, u })
.Where(g => this.GetSearchCriteria(g))
.Select(g => g);

Complex JPA query with nested JOINs using Criteria API

Suppose I have a SQL like that:
SELECT a.*
FROM A a
LEFT JOIN
B b
JOIN C c ON (c.b_id = b.id AND c.whatever > 0)
ON (a.id = b.a_id)
Now I start coding using the criteria API:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<A> criteria = builder.createQuery(A.class);
Root<A> a = criteria.from(A.class);
Now what?
I can't Join<A, B> b = a.join("b") yet.
The a.join(???) should be called over something else, that happens to have b defined.
That something else is the result of joining together B and C (plus a custom ON clause, stating that only some Cs - those with whatever bigger than zero - are acceptable). That something else still exposes B and C separately (for further predicate filtering with where and/or column projection with select).
UPDATE
What's the difference between
(1) A a LEFT JOIN (B b JOIN C c ON (c.b_id = b.id AND c.whatever > 0)) ON (a.id = b.a_id); and
(2) (A a LEFT JOIN B b ON (a.id = b.a_id)) JOIN C c ON (c.b_id = b.id AND c.whatever > 0)?
[parenthesis were added for clarity; they are never required]
The ON clause can be understood as "closing" the last "still open" JOIN. The JOIN clause (any type) can be understood as "opening" a new JOIN; these JOINs are stacked on "opening" and unstacked on "closing".
In (1), the order is: I-JOIN(B and C), then L-JOIN(A and that).
In (2), the order is: L-JOIN(A and B), then I-JOIN(that and C).
[I-JOIN is an INNER JOIN and L-JOIN is a LEFT OUTER JOIN]
For the sake of simplicity, just take the table C to be empty. So, no matter what JOIN you make, any reference to C (i.e. to its columns) will always be NULL.
Now, in (1) there will be one result per row in A. Because I-JOIN(B and C) will always produce no rows (remember, C is empty, so any INNER JOIN is empty too); then L-JOIN(A and empty) will produce A and all columns from B and C will be NULL.
In (2) the result will be totally empty. No matter how many rows L-JOIN(A and B) produces (there will be at least one row per row of A), the final INNER JOIN with empty C entails an empty result (no rows at all).

postgresql inner join duplicating some records

I have a large query developed as cte, in certain parts I have to make totals of secondary tables using inner joins to minimize the number of records processed, somehow two subqueries almost identical one works and the second duplicates 8 times some of the totalized records
I need to use inner join or the response time is shoots to the sky by 15x or more times
with
p0 as (select distinct on (pventa) pventa, p.tipo tpva from lecturas l
left join puntoventa p on l.pventa=p.numero where dia between '2017-10-01' and '2017-10-31' and p.tipo in ('A','E')),
r1 as (select p.tpva, l.pventa, dia, turno from lecturas l
inner join p0 p on p.pventa=l.pventa
where dia between '2017-10-01' and '2017-10-31'),
p1 as (select pva, remision, sum(abono), count(abono) from pagosremisiones p
inner join movsgas m on p.pva=m.pventa and p.remision=m.folio
inner join r1 r on r.pventa=m.pventa and r.dia=m.dia and r.turno=m.turno group by 1,2 order by 1,2 ),
f1 as (select c.serie, c.factura, sum(abono), count(abono) from chequefactura c
inner join movsgas m on c.serie=m.serie and c.factura=m.factura
inner join r1 r on r.pventa=m.pventa and r.dia=m.dia and r.turno=m.turno group by 1,2 order by 1,2 )
select * from p1
Nprem and ncheck are for debugging
P1 and f1 depend on r1, p1 works (as far as I've tried) without duplicate records (nprem corresponds to existing registers), however, ncheck increases on some records up to 8 times its actual values
I'm not sure if the correct p1's results are purely casual and don't know how to correct duplicates in f1
I do have the alternative of doing direct subqueries but I have a didactic interest in using joins
Btw, so far direct subqueries are much more efficient than the joins possibly because they have been poorly structured
What am I doing wrong?
What would you do to optimize the code?
Thanks in advance
Jose
the trick needed is the new subquery r2 including [ distinct on (serie, factura) ], if I omit it the error persists; duplicates in r2 do not correspond to the number of duplicates in f1, so I had no idea where so many came from; thank you all and again an apology for the terrible description of my problem
with
p0 as (select distinct on (pventa) pventa, p.tipo tpva from lecturas l
left join puntoventa p on l.pventa=p.numero where dia between '2017-10-01' and '2017-10-31' and p.tipo in ('A','E')),
r1 as (select p.tpva, l.pventa, dia, turno from lecturas l
inner join p0 p on p.pventa=l.pventa
where dia between '2017-10-01' and '2017-10-31'),
r2 as (select distinct on (serie, factura) m.serie,m.factura from movsgas m
inner join chequefactura c on c.serie=m.serie and c.factura=m.factura
inner join r1 r on r.pventa=m.pventa and r.dia=m.dia and r.turno=m.turno),
p1 as (select pva, remision, sum(abono) payp from pagosremisiones p
inner join movsgas m on p.pva=m.pventa and p.remision=m.folio
inner join r1 r on r.pventa=m.pventa and r.dia=m.dia and r.turno=m.turno group by 1,2 order by 1,2 ),
f1 as (select c.serie, c.factura, sum(abono) payfr2, count(*) from chequefactura c
inner join r2 r on r.serie=c.serie and r.factura=c.factura group by 1,2 order by 1,2 )

JPQL: Access to outer attributes in JOIN of subquery

In my JPA model there are 3 tables A, B, C.
My query is:
SELECT a FROM A a
WHERE EXISTS (
SELECT c from C c LEFT JOIN B b"
ON c = b.c AND b.a = a
WHERE c.date BETWEEN CURRENT_TIMESTAMP AND :pUntil AND b.a IS NULL
)
Background is that I want all entities of A that do not have an entry in b that is linked to an event C in the future.
The problem is that I get Column 'T0.ID' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or ...
EDIT
: Think of it as A is a user table, C are events, and B stores the registrations of users for events. I want to get all users, which have not registered for all future events until parameter pUntil.
Although I agree with Neil, I worked around this issue by changing my query. Here's the new query:
SELECT a FROM A a
WHERE EXISTS (
SELECT c from C c
WHERE c.date BETWEEN CURRENT_TIMESTAMP AND :pUntil
AND NOT EXISTS (
SELECT b from B b
WHERE b.c= c and b.a = a
)
)