How to do a Join Query on a Mysql fetch in JPQL - java

I have a table Users
Id(key) | username | some other cols...n
and a table Tokens:
userID, Token (k)
userID in Tokens is defined as being the foreign key from users.id.
What i want to do is to be able to : Given a Tokens.token, get the col info from Users.
the mysql command in SQL is like such:
select a.* from users a left join tokens b on a.User_Id = b.userId and b.userId = 1;
(i dont know if the above is optimal...but it returns what i want)
How would i replicate that in JPQL?
The simple select fetch command i am familar with is: (other than using the built in one)
String qlString = "Select p from Tokens p WHERE p.token=:token";
TypedQuery<Tokens> query = this.entityManager.createQuery(qlString,Tokens.class).setParameter("token", token);

When you use JPA, you don't mind for table and columns, you use Entities and Relations, the query must be:
select u.info from User u join u.tokens t where t.token = :token
This assumes:
#Entity class User {
#OneToMany List<Token> tokens;
String info;
}
#Entity class Token {
String token;
}
You start from User, then go with your attribute tokens to the Token entity, and filter for the Token attribute.
To get the list you use:
List<String> infos = entityManager.createQuery(YOUR_QUERY).list();

Related

Filter SQL rows that may be null

I'm trying to write a query in Kotlin Exposed that joins multiple tables together. Some of the tables can have null values, in which case the select statement should just ignore those.
On an example: I have a UserTable, a GeoLocationTable and a PhotoTable. A user will always have a referenced GeoLocation table, but it may or may not have photos. A UserTable doesn't know anything about the PhotoTable, but the PhotoTable has a userId as a FK.
I want to achieve that, when I query for the user - I always receive a user in the result set. The photos should only be in the result set if there are photos that have userId as a foreign key, and otherwise the result set should only contain the user.
My problem is that if photos for the user are not in the database, then my query doesn't even return the user! What am I doing wrong?
Here is the query.
private fun fetchUserWithPhotos(userId: String) = tx {
val query = UserProfileTable
.join(
joinType = JoinType.LEFT,
otherTable = GeoLocationTable,
otherColumn = GeoLocationTable.id,
onColumn = UserProfileTable.geoLocationId
)
.join(
joinType = JoinType.LEFT,
otherTable = PhotoTable,
otherColumn = PhotoTable.userId,
onColumn = UserProfileTable.id
)
val x = query
.select {
(UserProfileTable.id eq userId) and
(UserProfileTable.deletedAt.isNull()) and
(UserProfileTable.enabled eq true) and
(PhotoTable.userPhotoType eq UserPhotoType.PROFILE.toString()) and
(PhotoTable.position eq 1)
}
// x is empty set here, even though the user EXISTS!
}
How can I always get the user, and photos only if they are present?
I think I have this straight, the query I can parse from your code works out to this:
select * from user_profile
left join geo_location on user_profile.geo_location_id = geo_location.id
left join photo on user_profile.id = photo.user_id
where user_profile.id = ?
and user_profile.deleted_at is null
and user_profile.enabled is true
and photo.user_photo_type = 'PROFILE'
and photo.position = 1;
Your issue as described is: ' if photos for the user are not in the database, then my query doesn't even return the user! What am I doing wrong?'
Issue: You are using predicates based on data in the photo table, you've stated there isn't always a photo entry for a user. If there are no photos then the predicates are false and that row won't be selected, even if you know the user exists:
and photo.user_photo_type = 'PROFILE'
and photo.position = 1;
Proposed Solution: I think you can try to join photos that you want and maintain the predicates on the user table only. Update your query to:
select * from user_profile
left join geo_location on user_profile.geo_location_id = geo_location.id
left join photo on user_profile.id = photo.user_id and photo.position = 1 and photo.user_photo_type = 'PROFILE'
where user_profile.id = ?
and user_profile.deleted_at is null
and user_profile.enabled is true;

How to determine if two lists share any objects with Hibernate

I have this example SQL query that I created that tries to find all REPORTs that have an associated REPORT_PERMISSION object with one of the USER_GROUPs that the current user also has. So there are many REPORT_PERMISSION objects that tie a report to a group, and a user can have many groups, just one of those have to match up to allow the user to view the report. I'm just not sure how to write this in HQL
SELECT * FROM REPORT r
JOIN REPORT_PERMISSION rp
on r.id = rp.report_id and rp.user_group_id in
(SELECT l.user_group_id FROM USER_GROUP_LINK l where l.user_id = 2)
where r.type = 'GENERAL';
it should be something like :
Query reportQuery = entityManager.createQuery
("select distinct rep from Report rep
join rep.reportPermissions per
join per.userGroups gr
join gr.users u
where u.id = :userId and rep.type = 'GENERAL'");
reportQuery.setParameter("userId" , user.getId());
example mapping (names that are used in hql , and fileds name in mappings ) :
rep.reportPermissions -- Collection < ReportPermission> reportPermissions in Report;
per.userGroups -- Collection < UserGroup> userGroups in ReportPermission;
gr.users -- Collection < User> users in UserGroup;
u.id -- #Id Long id; in user class

Relationships between JPQL, Java (and the Oracle DB)

I am confused about the above relationship.
My Oracle DB Tables:
xd_Users: user_id (pk), client_id (fk), name, doj, email, dol
xd_Managers: manager_id (pk), user_id (fk)
Corresponding Java Entities User and Manager relate to the above two tables respectively. Manager and User are separate, not related by inheritance, and have fields that correspond to the DB tables.
In my application, a Manager has to be a User.
I am writing the a(n as yet unfinished) method (in a class called PersistService) to retrieve a list of users who are managers.
public static ArrayList<User> getManagersForClient(Client client) {
Long clientId = client.getClientId();
EntityManager em = getEntityManager();
String sqlQuery = "SELECT u FROM XD_USERS u, XD_MANAGERS m WHERE u.CLIENT_ID = :clientId";
TypedQuery<User> query = em.createQuery(sqlQuery, User.class);
query = query.setParameter("clientId", clientId);
ArrayList<User> clientUsers = (ArrayList<User>) query.getResultList();
for (User user : clientUsers) {
}
return clientUsers;
}
The pseudo-sql query I constructed was (:client_id at the end is just the java variable, hence the pseudo-sql):
select * from users u join managers m on u.user_id = m.user_id where u.client_id = :client_id;
I am having trouble converting this to a valid JPQL query. I don't understand how to think about solving this. In particular, the relationship between the identification variable, the single-valued relationship field, the collection-valued relationship field and the persistent field is very confusing. And I am even more confused by this post. Please help!
If you have coded the related entities correctly then your sql select query is something like this in jpql (according to the structure of related tables you gave):
select u.userId,u.name,u.doj,u.email, u.dol, m.managerId
from User u
join u.manager m
where u.clientId = :client_id;

How to create mapping of composed object with Hibernate when using a complex sqlquery?

I am trying to use the below query with Hibernate's session.createSQLQuery.
The Entity object corresponding to user has an attribute called address.
The address object is created out of 5 fields from table 'user'.
If I do not use an SQLQuery it gets filled auto-magically.
However without the SQLQuery I can't get all the info I would get from the desired joins shown below.
The user entity object also attributes like accessPlan which I am filling up using
.addEntity("accessPlan", AccessPlan.class)
Query:
SELECT
user.*,
ap.*,
country.*,
auth.*,
GROUP_CONCAT(coup.code SEPARATOR ' ') coupons
FROM
user
INNER JOIN access_plan ap ON (user.access_plan = ap.id)
INNER JOIN country ON (user.country=country.code)
LEFT JOIN user_auth auth ON (user.id = auth.userid)
LEFT JOIN (
SELECT
trans.user_id,coupon.code
FROM
payments_transaction AS trans
INNER JOIN payments_coupon coupon ON (trans.payments_coupon_id=coupon.id)
) coup ON (user.id=coup.user_id)
GROUP BY user.id;
What can be the easiest way to fill up the composed address object while using the SQLQuery?
OR
Is there a way to avoid using SQLQuery for a query like this?
Please check below example from the section 'Returning multiple entities'
String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
List loggedCats = sess.createSQLQuery(sql)
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class).list()
In your case, cat = user, mother = address... somewhat like that.
I do not have anything to try out at the moment but I guess this will help.

How do I port query with join across multiple tables from JDOQL to HQL

I am porting an application for KodoJDO to Hibernate.
I have a query that goes across 4 tables in the db, and 3 objects in the java code.
In English the query is Find the users that have entitlements in system X.
my JDOQL where clause called on the User object was
where entitlements.contains(ent) && (upper( ent.system.id ) = 'EVPN')
some sql that does the query is:
select unique(u.id)
from USER u, USERENTITLEMENT ue, ENTITLEMENT e, SYSTEM s
where u.id = ue.userid
and ue.entitlementid = e.id
and e.systemid = s.id
and s.id = 'evpn'
My best guess for HQL gives me an exception
org.hibernate.hql.ast.QuerySyntaxException: unexpected AST node: ( [select user from com.ebig.entity.User as user, com.ebig.entity.Entitlement as ent, com.ebig.entity.System as sys where entitlements.contains(ent) and ent.system = sys and sys.id = 'evpn']
the db is structured like this:
User
id
UserEntitlement
userid
entitlementid
Entitlement
id
systemid
System
id
the java code is structured as below:
class User
{
String id;
Set<Entitlement> entitlements;
}
class Entitlement
{
String id;
System system;
}
class System
{
String id;
}
Update My final query that works
hqlQuery = "select distinct user from User as user "+
"inner join user.entitlements as entitlement inner join entitlement.system as system "+
"where system.id = 'evpn' AND mod(user.flags, 2) = 0 AND source = 1";
Yes I know I should use parameters, but I have a great many problems to solve, and will post pone that code for another day.
Another variation with an implicit inner join for entitlement to system
hqlQuery = "select distinct user from User as user "+
"inner join user.entitlements as entitlement "+
"where entitlement.system.id = 'evpn' AND mod(user.flags, 2) = 0 AND source = 1";
You should use joins :
select distinct u.id from User u
inner join u.entitlements as entitlement
inner join entitlement.system as system
where system.id = :evpn
where :evpn is a named parameter that you have to bind.
You must think in terms of objects and relationships between objects when doing HQL, and not in terms of tables, foreign keys and join tables.

Categories

Resources