Using "having" on join clause of Spring JPA specification - spring

I have a repository of Users; each User has a OneToMany relationship with a collection of Posts.
How can I filter (and page) the repository of users by the number of posts they have using JPA specifications?
My initial attempt looked as such:
public static Specification<User> receiptNumberGreaterThanOrEqualTo(int numberToFilterBy) {
return (users, query, cb) -> greaterThanOrEqualTo(cb.count(users.get("posts")), Long.valueOf(numberToFilterBy));
}
This however caused an error to the effect of:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')>=9 limit 100'
This is because the #OneToMany join expects a HAVING clause to be used rather than WHERE, i.e. select * from users outer left join posts on users.id = posts.id having(count(posts) > someNumber) where user.id = "some-id"
vs
select * from users outer left join posts on users.id = posts.id where user.id = "something" and count(posts) > someNumber;
I can generate a query with the having keyword by creating a join between user and posts, and then doing as follows:
query.having(cb.greaterThanOrEqualTo(cb.count(joinOfPosts), Long.valueOf(numberToFilterBy))), but the type of this is CriteriaQuery, and I'm unsure how to turn this into a Specification.

I solved this by using the size() method on the criteriaBuilder,
ie.
(users, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(criteriaBuilder.size(users.get("posts")), numberToFilterBy);

Related

Criteria Query to retrieve data from DB using specification and predicate

I have two tables (user, vehicles) and i want to write criteria query to retrieve data from db using criteria query specification and predicate to both Join Tables.
select ur.id, count (ur.vehicle_FK) from user so
inner join VEHICLE vhe on vhe.user_id_FK = ur."ID"
group by ur.id, vhe.user_id_FK;
How to implement it using criteria query ??
Try something like this :
Criteria criteria = session.createCriteria(User.class, "user");
criteria.createAlias("user.vehicle_FK", "vehicle", Criteria.INNER_JOIN);
criteria.setProjection(
Projections.projectionList().add(Projections.groupProperty("user.id"))
.add(Projections.countDistinct("user.id")));
Parameters in Criteria Queries
The following query string represents a JPQL query with a parameter:
SELECT c FROM Country c WHERE c.population > :p
An equivalent query can be built using the JPA criteria API as follows:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Country> q = cb.createQuery(Country.class);
Root<Country> c = q.from(Country.class);
ParameterExpression<Integer> p = cb.parameter(Integer.class);
q.select(c).where(cb.gt(c.get("population"), p));
The ParameterExpression instance, p, is created to represent the query parameter. The where method sets the WHERE clause. As shown above, The CriteriaQuery interface supports method chaining. See the links in the next sections of this page for detailed explanations on how to set criteria query clauses and build criteria expressions.
You can find more examples here
https://www.objectdb.com/java/jpa/query/criteria
Remember to post an answer when you find one! :)

Laravel inject SQL Query into Model Collection

I have a Laravel Controller method with the following code:
$listings = LikedListing::where('user_id', '=', $user->id)
->with('Listing.Photos')
->get();
This should return a collection of LikedListing records with Photos attached to each likedlisting record.
I have this SQL Query I need to inject into each record as well:
select u.id, l.address, u.first_name, u.last_name, ll.score
from listings l
left join liked_listings ll on ll.listing_id = l.id
left join users u on u.id = ll.user_id
where u.id in (
select secondary_user
from user_relationships
where primary_user = $primaryUser
)
and ll.listing_id = $listingId
Where $primaryUser = $user->id And $listingId is equal to the listingid inside each record in the collection.
I have absolutely no idea how to do this.
Maybe theres a model way of performing this? UserRelationship model has a primary_user column, which connects to a $user->id, and there is a secondary_user column, which acts like a follower userid, which is what we need in the final result (a list of all related users per listing)`
Can someone who has much far superior knowledge with Laravel please assist
My goal is to have the current collection of listing records with associated photos as well as following users (secondary_user) from the user_relationship table related to the primary_user (the logged in user) who have a record using user_id with the secondary_user value for that listing in the likedlisting table (obv assoicated with the listing_id). I already provided a raw sql query if thats the only option.
So in simple terms all related users who have liked a listing that the primary user has liked as well should be added to each listing record

Inner Join and Group By using Specification in Spring Data JPA

I am trying to fetch the employee details whose empltype is clerk and whose joining date is the recent one.
For which the query looks like following in SQL Server 2008:
select
*
from
employee jj
inner join
(
select
max(join_date) as jdate,
empltype as emptype
from
employee
where
empltype='clerk'
group by empltype
) mm
on jj.join_date=mm.jdate and jj.empltype=mm.emptype;
I am using SpringData JPA as my persistence layer using QuerylDSL,Specification and Predicate to fetch the data.
I am trying to convert the above query either in QueryDSL or Specification, but unable to hook them properly.
Employee Entity :
int seqid;(sequence id)
String empltype:
Date joindate;
String role;
Predicate method in Specifcation Class :
Predicate toPredicate(Root<employee> root,CriteriaQuery <?> query,CriteriaBuilder cb)
{
Predicate pred=null;
// Returning the rows matching the joining date
pred=cb.equal(root<Emplyoee_>.get("joindate"));
//**//
}
What piece of code should be written in //**// to convert about SQL query to JPA predicate. any other Spring Data JPA impl like #Query,NamedQuery or QueryDSL which returns Page also works for me.
Thanks in advance
I wrote this in notepad and it hasn't been tested but I think you're looking for something like
QEmployee e1 = new QEmployee("e1");
QEmployee e2 = new QEmployee("e2");
PathBuilder<Object[]> eAlias = new PathBuilder<Object[]>(Object[].class, "eAlias");
JPASubQuery subQuery = JPASubQuery().from(e2)
.groupBy(e2.empltype)
.where(e2.empltype.eq('clerk'))
.list(e2.join_date.max().as("jdate"), e2.emptype)
jpaQuery.from(e1)
.innerJoin(subQuery, eAlias)
.on(e1.join_date.eq(eAlias.get("jdate")), e1.emptype.eq(eAlias.get("emptype")))
.list(qEmployee);

List of Users with their single Role in MVC 6 left joined

Using VS 2015, MVC 6 RC1 and EF 7 RC1 I'm trying to get a list of all users with their single role name.
I have tried all suggestions I have come across on StackOverflow but none have worked.
The SQL I'm looking for is:
SELECT [User].[Email], [Role].[Name]
FROM [User]
LEFT JOIN [UserRoles] ON [User].[Id] = [UserRoles].[UserId]
LEFT JOIN[Role] ON [UserRoles].[RoleId] = [Role].[Id]
I have written the below and tested on LinqPad (works fine) and should have worked in my project but comes up with an error:
var q1 = (from user in _context.Users
join ur in _context.UserRoles on user.Id equals ur.UserId into grp1
from fgrp1 in grp1.DefaultIfEmpty()
join r in _context.Roles on fgrp1.RoleId equals r.Id into grp2
from fgrp2 in grp2.DefaultIfEmpty()
select new { UserEmail = user.Email, UserRoleName = fgrp2.Name }).ToList();
And the error message is:
An unhandled exception occurred while processing the request.
InvalidOperationException: Sequence contains no elements
System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
I don't know if it makes any difference but I have created my own Role Entity as:
public class ExtranetRole : IdentityRole<int> { }
and my own User entity as:
public class ExtranetUser : IdentityUser<int> { }
Any help/suggestions much appreciated.
EF7 RC1 have some bugs, related to LEFT joins. Check https://github.com/aspnet/EntityFramework/issues/3629 - it looks very similar to your problem.
I think the best solution until EF release is just read all three tables separately and join them in memory using linq (to objects). Guaranteed to work :)

Spring Roo doesn't add FetchType.LAZY for fields in .aj files, Should I do it manually?

These are a couple of question, should Spring Roo through reverse engineering adding FetchType.LAZY for Set fields in .aj files or should I do it manually?
If FetchType.LAZY is not present at .aj files, I could make it through the queries " SELECT st1 FROM parentTable t1 JOIN FETCH t1.childTable st1" into the select, right ?
The point here is that I can add FetchType.LAZY to the files manually (Refactor .aj file > Push In..) and then on .java file (high risk if I want Roo to keep the control on my domain classes).
About to make it through queries, I can't do this because I'm getting:
> query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=ii,role=...domain.Industry.i18nIndustries,
tableName=..I18nIndustry,
tableAlias=i18nindust3_,
origin=..Industry industry2_,
columns={industry2_.IdIndustry ,className=..domain.I18nIndustry}}]
[select u.idUserName, u.isActiveInd, u.employeeNbr, u.name, c.name as CompanyName, ii.name as IndustryName from Users u JOIN u.idCompany c JOIN c.idIndustry i JOIN FETCH i.i18nIndustries ii WHERE u.idUserName = :username ]
Here the .aj files generated by Roo:
privileged aspect Users_Roo_DbManaged {
...
#ManyToOne
#JoinColumn(name = "IdCompany", referencedColumnName = "IdCompany", nullable = false)
private Company Users.idCompany; ...
..
privileged aspect Company_Roo_DbManaged {
...
#ManyToOne
#JoinColumn(name = "IdCity", referencedColumnName = "IdCity", nullable = false)
private City Company.idCity;
#ManyToOne
#JoinColumn(name = "IdIndustry", referencedColumnName = "IdIndustry", nullable = false)
private Industry Company.idIndustry; ..
..
privileged aspect Industry_Roo_DbManaged { ..
#OneToMany(mappedBy = "idIndustry")
private Set<I18nIndustry> Industry.i18nIndustries; ...
Can you please give me a clue, about what is happening here ?
Spring MVC 3.2,
Roo 1.2.4,
MSSql database
Thanks folks!
--JR
About
These are a couple of question, should Spring Roo through reverse engineering adding FetchType.LAZY for Set fields in .aj files or should I do it manually?
This is not needed because this is the default for this kind of relationship (see https://stackoverflow.com/a/13765381/2295657).
If FetchType.LAZY is not present at .aj files, I could make it through the queries " SELECT st1 FROM parentTable t1 JOIN FETCH t1.childTable st1" into the select, right ?
This makes a eager loading of the relationship data. I think you are in a mistake about the meaning of LAZY and EAGER modes:
EAGER: Requires to load value when instance is loaded into memory (default for basic and no-collections-relationship properties)
LAZY: when instance is loaded a proxy is stored in property and, when anything tries to get data, loads it form DB (default for collections-relationship properties)
On the other hand, to load a LAZY property requires a DB Connection alive when anything tries to get the data, so, you must execute this code inside a no-static, #Transactional annotated, method (read #Transactional JavaDoc for more info).
I advice you to make a look in the JPA specification. In my experience, I so useful.
I found whats happening, This is your HQL
[select u.idUserName, u.isActiveInd, u.employeeNbr, u.name, c.name as CompanyName, ii.name as IndustryName from Users u JOIN u.idCompany c JOIN c.idIndustry i JOIN FETCH i.i18nIndustries ii WHERE u.idUserName = :username ]
What i understand from this hql is u want to fetch list of i18nIndustries ii along with that perticuler idIndustry i correct?
But when you use JOIN FETCH on any object you have to select the main object to hold child object, in your case main object is idIndustry. JOIN FETCH i.i18nIndustries ii means "when fetching idIndustry, also fetch the i18nIndustries, linked to the idIndustry". But your query doesn't fetch idIndustry So the fetch makes no sense.
In select either u have to fetch i also so that the owner (i) of the fetched association (i.i18nIndustries ii) will present in the select list. as your error is
query specified join fetching, but the owner of the fetched
association was not present in the select list
or remove JOIN FETCH just use JOIN
So keeping in mind u want list of i18nIndustries ii, Your query will become :(added i in select)
select u.idUserName, u.isActiveInd, u.employeeNbr, u.name, c.name as
CompanyName, i,ii.name as IndustryName from Users u JOIN u.idCompany c
JOIN c.idIndustry i JOIN FETCH i.i18nIndustries ii WHERE u.idUserName
= :username

Resources