Hibernate - map multiple enums Set in query - java

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?

Related

How to select all fields of joined entities using hibernate?

I have two tables:
Limit_utilisation_history with fields:
bigint limit_utilisation_history_id (PK)
numeric(20,2) utilisation_amount
bigint limit_id (FK to limit_utilisation table)
Limit_utilisation with fields:
bigint limit_id (PK)
varchar customer_id
So both tables are related.
I need to expose the result of the following query via rest call:
select limit_utilisation_history_id, utilisation_amount, limit_id, customer_id
where customer_id in (some list of values)
I have done it in the following way:
#Entity
#Data
public class LimitUtilisation{
#Id
private Long limitIdl
private String customerId;
}
#Entity
#Data
#NamedQuery{
name = "LimitUtilisationHistory.getByCustomer",
query = "FROM LimitUtilisationHistory luh FETCH ALL PROPERTIES " +
"INNER JOIN luh.limitId al " +
"WHERE al.customerId in :values"
}
public class LimitUtilisationHistory{
#Id
private Long limitUtilisationHistoryId;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "limit_id", referencedColumnName = "limitId")
private LimitUtilisation limitId;
}
public interface LimitUtilisationHistoryRepository extends PagingAndSortingRepository<LimitUtilisationHistory, Long> {
#RestResource(path = "byCustomerId")
#Query
List<LimitUtilisationHistory> getByCustomer (#Param("values") List<String> customer);
}
It works fine, however when I call my rest endpoint I have only utilisation_amount value, others (mainly PK, FK, customer id are missing).
Does anyone have an idea how to do it correctly?
select limit_utilisation_history_id, utilisation_amount, limit_id, customer_id
where customer_id in (some list of values)
Remark: I cannot update DB structure. My intention is to only read from existing DB structure
As you you using FetchType.EAGER I don't see any reason of using FETCH ALL in the query, Could you please try with the below query :
select luh.limit_utilisation_history_id, luh.utilisation_amount, luh.limit_id, lu.customer_id
from LimitUtilisationHistory luh , LimitUtilisation lu
where luh.limit_id = lu.limit_id
and lu.customerId in :values

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();

how to retrieve association data in DAO?

My question is about how to retrieve association data in DAO.
I have 3 tables: user, role and user_role. user_role is the association table of user and role.
create table user (user_id varchar(50) not null primary key, password varchar(50) not null)
create table role (role_id int not null primary key, role_name varchar(50) not null)
create table user_role (user_role_id int not null primary key, user_id varchar(50) not null, role_id int not null)
I have 2 classes: User and Role. User has a roles property which is List of objects of Role type.
public class User {
private String userId;
private String password;
private List<Role> roles;
public String getUserId() { return this.userId; }
public void setUserId(String userId) { this.userId = userId; }
public String getPassword() { return this.password; }
public void setPassword(String password) { this.password = password; }
public List<Role> getRoles() { return this.roles; }
public void setRoles(List<Role> roles) { this.roles = roles; }
}
public class Role {
private int roleId;
private String roleName;
public int getRoleId() { return this.roleId; }
public void setRoleId(int roleId) { this.roleId = roleId; }
public String getRoleName() { return this.roleName; }
public void setRoleName(String roleName) { this.roleName = roleName; }
}
Now I am trying to build DAOs and getting confused on how to populate roles property of User class.
I think I need these DAO methods for User class:
1) User getUserMethod1(String userId) - retrieve a row from user table for a specific user_id. Dont populate roles property of User class.
2) User getUserMethod2(String userId) - retrieve a row from user table for a specific user_id. Also populate roles property of User class.
3) void updateUser(String userId) - update a row in user table for a specific user_id.
4) void deleteUser(String userId) - delete a row in user table for a specific user_id.
I think I need these DAO methods for Role class:
1) Role getRole(int roleId) - retrieve a row from role table for a specific role_id.
2) List<Role> getAllRoles() - retrieve all rows from role table.
3) void updateRole(int roleId) - update a row in role table for a specific role_id.
4) void deleteRole(int roleId) - delete a row in role table for a specific role_id.
Out of the above 8 DAO methods I am having issue with User getUserMethod2(String userId) method.
I can retrieve 1 row from user table for the specific user_id; then retrieve all role_id associated to that specific user_id from user_role table.
But then do I have to loop through them and call Role getRole(int roleId) method of Role class for each role_id?
If yes then how can I get a hold of that method? If not then what is the solution?
Is there a better way to solve this issue then calling Role getRole(int roleId) method of Role class for each role_id?
Thank you for reading this question.
If you have set your hibernate.cfg properly, you must have that one-to-many associations to associate your set in the user class.
<set name="role" table="role" inverse="true" lazy="true" fetch="select">
<key>
<column name="role_id" />
</key>
<one-to-many class="com.model.Role" />
</set>
Anyways, if this has been done correctly, you can enable lazy loading to not bring sets and only bring them when you try and access them. Note that you will have to keep the session open for lazy loading to work.
For question 2: you can use "fetch" in your hibernate query to specify eager loading of your set.
You can use criteria API or HQL to handle cases like to bring users who have no roles associated with them.

Using Map in Hibernate is not working

I am trying to create a simple program by using java.util.Map. I have created a Customer entity class with a map of Order classes. Here are my Java classes:
Customer.java
#Entity
public class Customer {
#Id
#GeneratedValue
private Integer id;
#OneToMany(mappedBy = "customer")
#MapKey(name = "orderNumber")
private Map<String, Order> orders;
}
Order.java
#Entity
#Table(name="TB_ORDER")
public class Order {
#Id
#GeneratedValue
private Integer id;
private String orderNumber;
#ManyToOne
private Customer customer;
}
Here is my program that tries to save a customer with some orders and then I am trying to display the saved data:
public class AppTest {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
saveCustomer(session);
session = HibernateUtil.getSessionFactory().getCurrentSession();
showCustomer(session);
HibernateUtil.getSessionFactory().close();
}
private static void showCustomer(Session session) {
session.getTransaction().begin();
List<Customer> list = session.createQuery("from Customer").list();
for (Customer customer : list) {
System.out.println("customer id : "+customer.getId()+ ", customer orders : "+customer.getOrders());
}
session.getTransaction().commit();
}
private static void saveCustomer(Session session) {
session.getTransaction().begin();
Customer customer = new Customer();
Order order = new Order();
order.setCustomer(customer); order.setOrderNumber("100");
Map<String, Order> map = new HashMap();
map.put("100", order);
customer.setOrders(map);
session.save(customer); session.save(order);
session.getTransaction().commit();
}
}
After running the program, Hibernate generated below DDL & DML commands:
Hibernate: create table Customer (id number(10,0) not null, primary key (id))
Hibernate: create table TB_ORDER (id number(10,0) not null, orderNumber varchar2(255 char), customer_id number(10,0), primary key (id))
Hibernate: alter table TB_ORDER add constraint FK_qr7tjivmclv5trf0sbwxki4v foreign key (customer_id) references Customer
Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TB_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
Hibernate: select customer0_.id as id1_0_ from Customer customer0_
customer id : 1, customer orders : null
Hibernate generated only single select query to get the Customer details but not getting any data from TB_ORDER table. So when I try to get the Orders from Customer I am getting null. Please let me know where is the mistake in this code.
It looks like you are missing the #JoinColumn annotation through which you tell who is the owner of the relationship. For this reason i think you should change the class order like this:
#Entity
#Table(name="TB_ORDER")
public class Order {
#Id
#GeneratedValue
private Integer id;
private String orderNumber;
#ManyToOne
#JoinColumn(name = "customer_id")
private Customer customer;
}
And should work fine.
You have to also use #MapKeyJoinColumn as well its better to initialize your Map in pojo and try again .
private Map<String, Order> orders =new Map<String, Order>();

Hibernate like query on Many-to-Many collection

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();

Categories