Select username and role name - jpa

As the title indicates I'm trying to select both username and role name by using the following query.
select u.username, r.name
from users u, role r
inner join users_roles ur
on ur.user_id = u.id
where username = ?;
However I'm getting the below error
[2017-04-05 21:34:49] [42P01] ERROR: invalid reference to FROM-clause entry for table "u"
[2017-04-05 21:34:49] Hint: There is an entry for table "u", but it cannot be referenced from this part of the query.
[2017-04-05 21:34:49] Position: 79
My user entity is as follows
#Entity(name = "users") // Postgres doesn't like the table name "user"
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String username;
...
#ManyToMany
#JoinTable(
name = "users_roles",
joinColumns = #JoinColumn(
name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(
name = "role_id", referencedColumnName = "id"))
private Collection<Role> roles;
...
And my role entity is as follows
#Entity
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#ManyToMany(mappedBy = "roles")
private Collection<User> users;
...
Any clues about what I'm doing wrong?

SELECT users.username, role.name
FROM users
LEFT OUTER JOIN users_roles
ON users.id = users_roles.user_id
LEFT OUTER JOIN role
ON users_roles.role_id = role.id
WHERE username = ?

Related

JPA expecting ID column on joined table

I'm attempting to represent a join table with JPA, however the generated SQL is expecting an id field on one of the tables.
The generated SQL is very close, but appears an ID column is expected on Permission table and used as the FK on the join table, which I was hoping not to do. See schema below:
You can see I am not using an ID column on permission table, instead letting the text representation of the permission be the key.
User.java
#Entity
#Data
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int accountId;
private String name;
private String email;
private String password;
private boolean admin;
#ManyToMany
#JoinTable(
name = "user_permission",
joinColumns = #JoinColumn(name = "id"),
inverseJoinColumns = #JoinColumn(name = "permission"))
private List<Permission> permissions;
}
Permission.java
#Data
#Entity
public class Permission {
#Id
private String permission;
private String permissionName;
private String permissionDescription;
}
Generated SQL
select
permission0_.id as id1_2_0_,
permission0_.permission as permissi2_2_0_,
permission1_.permission as permissi1_0_1_,
permission1_.permission_description as permissi2_0_1_,
permission1_.permission_name as permissi3_0_1_
from user_permission permission0_
inner join permission permission1_ on permission0_.permission=permission1_.permission
where permission0_.id=?
Error
ERROR 15056 --- [tp1962586186-25] o.h.engine.jdbc.spi.SqlExceptionHelper : Unknown column 'permission0_.id' in 'field list'
The problem was join columns name. It should have been mapped to the mapping tables FK instead of the parent tables PK. Above example is fixed with this change
#ManyToMany
#JoinTable(
name = "user_permission",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "permission"))
private List<Permission> permissions;

Inner join 3 tables in JPA with where clause

I'm struggling to make a query that inner join 3 tables and have a where clause. It's like my where doesn't exist.
Here are my entities:
CarModel entity:
#Entity
#Table(name = "CARMODEL")
public class CarModel implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy = "carModel")
private List<MyCars> myCars;
MyCars entity
#Entity
#Table(name = "MYCARS")
public class MyCars implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne
#JoinColumn(name = "CarModel_id")
private CarModel carModel= new CarModel();
#ManyToOne
#JoinColumn(name = "user_id")
private User user = new User();
User entity:
#Entity
#Table(name = "USER")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy = "user")
private List<MyCars> myCars;
Here is the graphical representation of these three entities:
And here is one of the queries i have tried:
public List<CarModel> findMyCarsByUserId(long IdUser)
{
String requete = "SELECT DISTINCT cm\n" +
"FROM MyCars ms\n" +
" INNER JOIN CarModel cm INNER JOIN User u where u.id=2";
Query query = em.createQuery(requete);
//query.setParameter("iduser", IdUser);
List<CarModel> cars = null;
cars = (List<CarModel>) query.getResultList();
return cars;
}
So here I'm trying to get all the ModeleVehicule for a given user_id. But I keep having all the ModeleVehicule of the table, despite the where clause.
I have a mysql query working for what I want:
SELECT cm.marque,cm.modele, cm.motorisation, cm.anneeModele, cm.puissance
FROM carmodel cm
INNER JOIN mycars ms ON cm.ID = ms.ModeleVehicule_id
INNER JOIN user u ON ms.user_id = u.ID
WHERE ms.user_id = 1
What am I doing wrong ?

JPQL to filter by OneToMany relationship that uses a join table

I'm trying to write a JPQL to fetch Users with some Roles by filtering by Role.Name.
public class User
#ManyToMany
#JoinTable(
name = "UsersRoles",
joinColumns = {#JoinColumn(name = "UsersId", referencedColumnName = "UsersId")},
inverseJoinColumns = {#JoinColumn(name = "RolesName", referencedColumnName = "Name")})
#BatchSize(size = 20)
private Set<Role> roles = new HashSet<>();
}
public class Role {
#Id
#Column(name = "Name", length = 50)
private String name;
}
I tried the following on #Query in the jpa repository
SELECT U FROM User U INNER JOIN Role R WHERE R.name = ?1
But that is not working and it generates sql like the following.
select
...
from Users user0_
inner join Roles role1_ on
where role1_.Name = ?
The joining condition is not added.

Using the Criteria API and Metamodel API to Join two Middle table always cross join

This is a RBAC module,There is three basic table user,role and permission and middle mapping table user_role and role_permission.
#Entity
#Table(name = "USER")
public class User implements Serializable {
#Id
private String userId;
...
}
#Entity
#Table(name = "ROLE")
public class Role implements Serializable {
#Id
private String roleId;
...
}
#Entity
#Table(name = "PERMISSION")
public class Permission implements Serializable {
#Id
private String permissionId;
...
}
#Entity
#Table(name = "USER_ROLE")
public class UserRole implements Serializable {
#Id
#GenericGenerator(name = "uuidGenerator", strategy = "uuid")
#GeneratedValue(generator = "uuidGenerator")
#Column(name = "ID")
private String id;
#ManyToOne
#JoinColumn(name = "USERID")
private User user;
#ManyToOne
#JoinColumn(name = "ROLEID")
private Role role;
...
}
#Entity
#Table(name = "ROLE_PERMISSION")
public class RolePermission implements Serializable {
#Id
private String id;
#ManyToOne
#JoinColumn(name = "PERMISSIONID")
private Permission permission;
#ManyToOne
#JoinColumn(name = "ROLEID")
private Role role;
...
}
and now i want to find all permission by user.id, SQL express like this:
select rp.* from Role_Permission rp,User_Role ur where ur.roleId = rp.roleId and ur.userId = :id
but by Criteria API:
public Predicate toPredicate(Root<RolePermission> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> predicates = new ArrayList<Predicate>();
if (StringUtil.isNotEmpty(userId)) {
final Root<UserRole> userRoleRoot = criteriaQuery.from(UserRole.class);
Join<RolePermission,UserRole> join = root.join("role", JoinType.INNER);
Predicate predicate = criteriaBuilder.equal(join.get("roleId"), root.get("role").get("roleId"));
predicate = criteriaBuilder.and(predicate,criteriaBuilder.equal(userRoleRoot.<UserRole>get("user").get("id"), userId));
predicates.add(predicate);
}
return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
}
and query build result is:
select count(rolepermis0_.id) as col_0_0_ from role_permission rolepermis0_ inner join role role2_ on rolepermis0_.roleid=role2_.roleid cross join user_role userrole1_ where role2_.roleid=rolepermis0_.roleid and userrole1_.userid=?
but why here role_permission cross join user_role, how role_permission join user_role by criteria API ?
thanks a lot.
final Subquery<UserRole> userRoleSubquery = criteriaQuery.subquery(UserRole.class);
final Root<UserRole> userRole = userRoleSubquery.from(UserRole.class);
userRoleSubquery.select(userRole.<UserRole>get("id"));
userRoleSubquery.where(criteriaBuilder.equal(root.get("role").get("roleId"), userRole.get("role").get("roleId")), criteriaBuilder.equal(userRole.get("user").get("id"), userId));
Predicate predicate = criteriaBuilder.exists(userRoleSubquery);
predicates.add(predicate);

JPA Criteria Subquery on JoinTable

How do I create an efficient JPA Criteria query to select a list of entities only if they exist in a join table? For example take the following three tables:
create table user (user_id int, lastname varchar(64));
create table workgroup (workgroup_id int, name varchar(64));
create table user_workgroup (user_id int, workgroup_id int); -- Join Table
The query in question (what I want JPA to produce) is:
select * from user where user_id in (select user_id from user_workgroup where workgroup_id = ?);
The following Criteria query will produce a similar result, but with two joins:
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> root = cq.from(User.class);
cq.select(root);
Subquery<Long> subquery = cq.subquery(Long.class);
Root<User> subroot = subquery.from(User.class);
subquery.select(subroot.<Long>get("userId"));
Join<User, Workgroup> workgroupList = subroot.join("workgroupList");
subquery.where(cb.equal(workgroupList.get("workgroupId"), ?));
cq.where(cb.in(root.get("userId")).value(subquery));
getEntityManager().createQuery(cq).getResultList();
The fundamental problem seems to be that I'm using the #JoinTable annotation for the USER_WORKGROUP join table instead of a separate #Entity for the join table so it doesn't seem I can use USER_WORKGROUP as a Root in a criteria query.
Here are the entity classes:
#Entity
public class User {
#Id
#Column(name = "USER_ID")
private Long userId;
#Column(name = "LASTNAME")
private String lastname;
#ManyToMany(mappedBy = "userList")
private List<Workgroup> workgroupList;
}
#Entity
public class Workgroup {
#Id
#Column(name = "WORKGROUP_ID")
private Long workgroupId;
#Column(name = "NAME")
private String name;
#JoinTable(name = "USER_WORKGROUP", joinColumns = {
#JoinColumn(name = "WORKGROUP_ID", referencedColumnName = "WORKGROUP_ID", nullable = false)}, inverseJoinColumns = {
#JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID", nullable = false)})
#ManyToMany
private List<User> userList;
}
As far as I know, JPA essentially ignores the join table. The JPQL that you do would be
select distinct u from user u join u.workgroupList wg where wg.name = :wgName
for the Criteria query, you should be able to do:
Criteria c = session.createCriteria(User.class, "u");
c.createAlias("u.workgroupList", "wg");
c.add(Restrictions.eq("wg.name", groupName));
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
there's no need to worry about the middle join table.