Hibernate like query on Many-to-Many collection - java

I am having Userentity which has mapped to user_roles. I want to filter these roles based on User.idand roles.name
Same like as this SQL query
SELECT ur
FROM user
JOIN user_roles ur
ON ur.user_id = user.id
WHERE user.id = 1
AND ur.name like '%admin%';
How to achieve this SQL query in hibernate?
How to pass parameter to role name?
User.java
#Entity
class User {
#ManyToMany
#JoinTable(name="user_roles",
joinColumns=#JoinColumn(
name="user_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(
name="role_id", referencedColumnName="id")
)
public Set<Role> getRoles() {
return roles;
}
}

Hope it will help
select "your_req" from User us join usr.role usr where usr.name like '%admin%' and us.id=1

HQL supports exactly what you want, you can create an HQL query and then pass parameters to it. The following code block may be a reference:
Long userId = 1L;
String roleNamePattern = "%admin%";
Query query = session.createQuery("SELECT role FROM User user JOIN user.roles role WHERE user.id = :userid AND role.name LIKE :rolename");
query.setLong("userid", userId);
query.setString("rolename", roleNamePattern);
List<Role> roles = query.list();

Related

Is it possible to create queries with AND without entity classes in the same method? (JPA + Hibernate)

I have a query method that I am attempting to define, however I am currently facing a problem. The query I am attempting to make is one that gets all users in my DB but filters out users with an admin role. I have an entity class for User and another for Role. My User class has fields for a users id, username, and email while the 'Role' entity contains a role id and role name as fields. Inside my user class entity, I define a many to many relationship defined as follows:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable( name = "user_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>();
The catch is that this is also where the user_roles table is generated, so I do not have an entity class related to user_roles.
So basically I am wondering if it is possible to create a query that uses values with and without entitles in the same method and if I need to use prepared statements in it?
#Query("SELECT u.id,u.username,u.email FROM User u,Role r, user_role ur WHERE u.id=ur.id AND r.id=ur.id AND r.name<>\'ADMIN\'")
List<User> getUsers();
I am currently getting an error user_role is not mapped [SELECT u.id,u.username,u.email FROM com.Application.models.User u,com.Application.models.Role r, user_role ur WHERE u.id=ur.id AND r.id=ur.id AND r.name<>'ADMIN'].
You can do this with a JPA inner join. It will traverse the join table for you.
#Query("SELECT u.id, u.username, u.email FROM User u join u.roles r where r.name <> 'ADMIN'")

How do I access a many-to-many table in jpa?

This is the user class with a #manytomany mapping, I want it to be unidirectional.
#Entity
#Getter
#Setter
#Table(name="users")
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany
#JoinTable(name="user_drivers", joinColumns=#JoinColumn(name="user_id"), inverseJoinColumns=#JoinColumn(name="driver_id"))
private Set<Driver> driverSet;
public User() {
}
}
A table is created with both keys from user and driver, but I don't know how to access it within my repository.
#Query(value="select u.user_id from user_drivers")
List<?> findAllByIdAndDriver(Long id);
This gives an error: Can't resolve symbol 'user_drivers'
#Query(value="select id,driverSet from User ")
List<?> findAllByIdAndDriver(Long id);
And this results in a nester query exception.
Your method naming is confusing. When you say something like findByIdAndSomethingElse you're implying that you're doing this:
SELECT * FROM MY_TABLE WHERE ID = ? AND SOMETHING_ELSE = ?;
There's missing information here, since you don't share your complete repository or Driver implementations, but assuming you want all user IDs from a Driver with a specific ID, you can simply do this:
#Query("select driver.userId from Driver driver where driver.id = ?1")
public List<Long> findUserIdsByDriverId(long id);
The ?1 is the first argument. You can refer to subsequent arguments with ?2, ?3, ... , ?n
I think the correct queries should be like:
#Query(value="select u.userId from UserDrivers u")
and
#Query(value="select u.id, u.driverSet from User u")
For the 1st query, I'm assuming that entity for the other table is called UserDrivers and its column - userId (according to Java naming conventions).
Found what I needed thanks to the answers pointing me in the right direction.
#Query(value="select u.driverSet from User u where u.id=?1")
List<?> getDriverSet(Long id);

Hibernate - map multiple enums Set in query

I have following tables:
user
- id BIGINT
- name VARCHAR
user_roles
- id BIGINT
- user_id BIGINT - FK TO USER
- name VARCHAR (name of the role)
so by using this we can assign multiple roles to user. In Java there is UserRole enum. How can I load in Hibernate user records with assigned roles?
I have following code
private Set<UserRole> userRoles;
#ElementCollection(targetClass=UserRole.class)
#Enumerated(EnumType.STRING)
#CollectionTable(name="user_role")
#Column(name="name")
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles= userRoles;
}
and I make the query like this:
CriteriaBuilder criteriaBuilder = sessionFactory.getCurrentSession().getCriteriaBuilder();
CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class);
Root<User> queryRoot = criteriaQuery.from(User.class);
queryRoot.join("userRoles", JoinType.LEFT);
TypedQuery<User> query = sessionFactory.getCurrentSession().createQuery(criteriaQuery);
return query.getResultList();
Query runs but when I try to access the roles Set it says
com.sun.jdi.InvocationException occurred invoking method.
What am I doing wrong?

Finding mutual friends of the same entity

I would like to be able to get mutual friends of both users in hql.
Is there any way to do it with h2 db.
I'm using spring-boot 1.5.6 with h2 embedded db.
Below is my User entity.
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private Long id;
#Version
#Column(name="version")
private int version;
#NotNull
#Column(name="username", nullable=false, unique=true)
private String username;
#Column(name="email", nullable=false, unique=true)
private String email;
#Column(name="password", nullable=false)
private String password;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "friends")
private Set<User> friends;
and repository
public interface UserRepository extends PagingAndSortingRepository<User, Long>{
User findByEmailAndPassword(String email, String password);
Here's my latest try which gives me the exception for some reason.
#Query("Select friends from User U join U.friends friends where size (friends.username) > 1 and exists (select friends from User U1 join U1.friends friends1 where friends1.username = ?1) and exists (select friends from User U2 join U2.friends friends2 where friends2.username = ?2)")
List<User> findMutualFriends(String username, String friend);
And when I try to get only duplicate values from it I get the exception. Can't access friends of username even though I'm using join on them. Here's stack trace:
Caused by: org.h2.jdbc.JdbcSQLException: Column "USER2_.USER_ID" not found; SQL statement:
select user2_.id as id1_4_, user2_.acc_status as acc_stat2_4_, user2_.email as email3_4_, user2_.gender as gender4_4_, user2_.password as password5_4_, user2_.username as username6_4_, user2_.version as version7_4_ from user user0_ inner join friends friends1_ on user0_.id=friends1_.user_id inner join user user2_ on friends1_.friends_id=user2_.id where (select count(user2_.user_id) from friends friends1_, user user2_ where user0_.id=friends1_.user_id and friends1_.friends_id=user2_.id)>1 and (exists (select user2_.id as id1_4_ from user user3_ inner join friends friends4_ on user3_.id=friends4_.user_id inner join user user5_ on friends4_.friends_id=user5_.id where user5_.username=?)) and (exists (select user2_.id as id1_4_ from user user6_ inner join friends friends7_ on user6_.id=friends7_.user_id inner join user user8_ on friends7_.friends_id=user8_.id where user8_.username=?)) [42122-196]
Any idea how to do it cause I couldn't find the answer. Maybe it can be done easier but I'm new to hql and can't figure it out.
Thanks.

Custom hibernate criteria (one-to-many relationship)

I need to create custom Hibernate query.
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> user = criteria.from(User.class);
List<Predicate> restrictions = new ArrayList<>();
restrictions.add(builder.equal(user.get("firstname"), user.getFirstName()));
List<User> users = (List<User>) entityManager.createQuery(criteria).getResultList();
I need to add to restrictions additional criteria. I have additional model Photo, which connected to model User with foreign key user_id.
I need to find users, which has any photos.
User model contains:
private List<Photo> photos;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "photo", cascade = CascadeType.ALL)
#Fetch (FetchMode.SELECT)
#JsonIgnore
public List<Photo> getPhotos() {
return photos;
}
Photo model contains:
private User user;
#ManyToOne
#JoinColumn(name="user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
UPDATED
I need something like this:
restrictions.add(builder.isNotNull(user.get("photos")));
but it's not working.
Problem is not with how to combine 2 restrictions, problem with how to add restriction isNotNull... User know nothing about photos. Photos know about user as they has user_id.
UPDATED2:
org.postgresql.util.PSQLException: ERROR: syntax error at or near "."
SQL:
select * from User user0_ cross join Photo photos1_ where user0_.id=photos1_.user and (. is not null)
I need follow SQL:
SELECT DISTINCT user.* FROM user
LEFT JOIN photo
ON user.id = photo.user_id;
Try this:
restrictions.add(Restrictions.and(Restrictions.eq(user.get("firstname"), user.getFirstName()),Restrictions.isNotNull(user.get("photos")));
UPDATE: The bidirectional relationship you are looking for is something like this:
Photo class:
#ManyToOne
#JoinColumn(name="user")
private User user;
User class:
#OneToMany(mappedBy="user")
private Set<Photo> photos;
In this one you have it mapped both ways so you can access photos from the user and user from photos.
I found solution myself. Full code:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> user = criteria.from(User.class);
Root<Photo> photo = criteria.from(Photo.class);
List<Predicate> restrictions = new ArrayList<>();
restrictions.add(builder.equal(user.get("firstname"), user.getFirstName()));
restrictions.add(builder.equal(user.get("id"), photo.get("user")));
List<User> users = (List<User>) entityManager.createQuery(criteria).getResultList();

Categories