[EDIT] Found the solution :
The problem was that the primary key is the field username. It seems that Hibernate doesn't handle this case. So I switched the primary key to an another field to fix it and it works !
I'm trying to use encryption on my database but I have some problems when I want to get the data.
The column transformer isn't used in the select clause but is working in the where clause.
This error appears when the query is a select * of the table like :
public interface UserRepository extends JpaRepository<User, String> {
#Query(value = "select a from User as a where username = :username")
AdminUser findByUsername(#Param("username") String username);
}
(The #Query is useless in this case but it's to have an example)
The generated query by Hibernate looks like :
SELECT user0_.username AS username1_0_, user0_.creation_date AS creation2_0_, user0_.last_update_date AS last3_0_, user0_.enabled AS enabled4_0_, AES_DECRYPT(user0_.email, unhex('myKey'),'myVector') AS email5_0_, user0_.password AS password6_0_, user0_.password_expiration_date AS password7_0_, user0_.profil_id AS profil8_0_
FROM my_user_table user0_
WHERE AES_DECRYPT(user0_.username, unhex('myKey'), 'myVector') = 'userTest';
In case of a query like :
#Query(value = "select a.username from User as a where username = :username")
The select clause is decrypted.
Any ideas why Hibernate doesn't use the columnTransformer in the select ?
Thanks,
#Table(name = "my_user_table")
public class User extends AbstractEntity implements UserDetails {
#Id
#Column(name = "username", nullable = false, unique = true, columnDefinition = "${encryption.column.definition}")
#ColumnTransformer(
forColumn = "username",
read ="${User.username.read}",
write ="${User.username.write}")
private String username;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "email", nullable = false, columnDefinition = "${encryption.column.definition}")
#ColumnTransformer(
read ="${User.email.read}",
write ="${User.email.write}")
private String mailAddress;
#Column(name = "password_expiration_date", nullable = false)
private Date passwordExpirationDate;
#OneToMany(targetEntity = OldPassword.class, fetch = FetchType.LAZY, cascade = { CascadeType.ALL }, orphanRemoval = true)
#JoinColumn(name = "username", nullable = true)
#OrderBy("creationDate desc")
private List<OldPassword> oldPasswords;
/**
* Use this field to enable or disable an account manually
*/
#Column(name = "enabled", columnDefinition = "bit default 0", nullable = false)
private boolean enabled;
#Transient
private Collection<? extends GrantedAuthority> authorities;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "profil_id", referencedColumnName = "id")
private Profil profil;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "user_places", joinColumns = #JoinColumn(name = "username"))
private List<String> userPlaces;
}
Related
I've been hitting my head in the wall for couple of days to figure out how to get partial result from #ManyToMany realtion from Criteria query. There are two entities:
public class UserEntity {
#Id
private Integer userId;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.DETACH)
#JoinTable(
name = "user2brand",
joinColumns = {#JoinColumn(name = "user_id", nullable = true)},
inverseJoinColumns = {#JoinColumn(name = "brand_id", nullable = true)}
)
private List<BrandEntity> brands;
....
}
public class BrandDTO {
#Id
#Column(name = "brand_id", unique = true, nullable = false)
private Integer brandId;
#Column(name = "brand_name", length = 128)
private String brandName;
...
}
public List<UserEntity> listUsersByBrand(List<Integer> brandIds) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<UserEntity> query = cb.createQuery(UserEntity.class);
Root<UserEntity> root = query.from(UserEntity.class);
final ListJoin<BrandEntity, UserEntity> brands = root.joinList("brands", JoinType.INNER);
CriteriaBuilder.In<Integer> inClauseBrand = cb.in(brands.get("brandId"));
inClauseBrand.value(brandIds);
query.select(root).distinct(true).where(inClauseBrand);
return result.getResultList();
}
And here is my problem - when using criteria query on the UserEntity i can add where clause to get the users which are related to a specific brand. However when getting the resultList from the query each UserEntity has all the brands that it relates to but not only the ones that are in the where clause. C
Can this be achieved using criteria query or I should go with native query ?
I have two tables Company and Employees, one-to-many mapping. Company table contains composite primary key.
I want to search from company table based on primary id but want to put an additional check on the child table.
I want to load only a particular type of employees which I will get in the request. How it can be done in Sprongboot JPA with findById("id");
class Company{
#Id
private String companyId;
#Id
private String stateId;
private String company Name;
#OneToMany(targetEntity = Employees.class, fetch = FetchType.LAZY, cascade = {
CascadeType.ALL }, mappedBy = "company")
private Set<Employees> empList;
}
class Employees{
#Id
private String id;
//foreign key
private String companyId;
//foreign key
private String stateId;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "companyId", referencedColumnName = "companyId", insertable = false, updatable = false, nullable = true),
#JoinColumn(name = "stateId", referencedColumnName = "stateId", insertable = false, updatable = false, nullable = true) })
private Company company;
private int salary;
private String type;
}
Use Filter, which is an alternative of #Where where you can set dynamic value.
Here is the sample
#FilterDef(
name = "employeeTypeFilter",
parameters = #ParamDef(name = "type", type = "string")
)
#Filter(
name = "employeeTypeFilter",
condition = "type > : type"
)
public class Employees {
}
You can enable or disable filter from your code dynamically based on your requirement.
You can use #Where for fixed type
#Where(clause = "type = 'anyEmployeeType'")
private Set<Employees> empList;
For dynamically fetch you can query in Employees repository
List<Employees> findByTypeAndCompany(String type, Company company);
I am implementing a user management system which has the following entities :
public class UserEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
Long id;
#Column(unique = true, name = "EMAIL")
private String email;
#Column(name = "NAME")
private String name;
#Column(name = "PASSWORD")
private String password;
#Column(name = "MOBILE")
private String mobile;
#Column(name = "OWNER_ID")
private String ownerId;
#Column(name = "TRAINER_ID")
private String trainerId;
#Column(name = "ADDED_ON")
private Timestamp addedOn;
#Column(name = "MODIFIED_ON")
private Timestamp modifiedOn;
#Column(name = "ADDED_BY")
private String addedBy;
#Column(name = "MODIFIED_BY")
private String modifiedBy;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "USER_ROLES", joinColumns = #JoinColumn(name = "USER_ID", referencedColumnName = "ID"),
inverseJoinColumns =
#JoinColumn(name =
"ROLE_ID", referencedColumnName = "ROLE_ID"))
List<RoleEntity> roles;
#OneToOne(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private UserStatisticsEntity userStatisticsEntity;
here is the RoleClass :
public class RoleEntity implements GrantedAuthority {
#Id
#Column(name="ROLE_ID")
private String roleId;
#Column(name="ROLE_NAME")
private String roleName;
#ManyToMany(mappedBy = "roles")
private List<UserEntity> users;
#Override
public String getAuthority() {
return this.roleId;
}
}
I would like to fetch all users belonging to a particular role and also be able to add dynamic where clauses on name, mobile, email along with paging etc.
My current code looks like this to fetch selected fields of Users with dynamic where clauses and pagination :
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<TrainerDTO> criteriaQuery = criteriaBuilder.createQuery(TrainerDTO.class);
Root<UserEntity> main = criteriaQuery.from(UserEntity.class);
criteriaQuery.multiselect(main.get("id"), main.get("name"), main.get("email"), main.get("ownerId"), main.get(
"mobile"),
main.get("addedBy"), main.get("modifiedBy"), main.get("addedOn"), main.get("modifiedOn"))
.orderBy(criteriaBuilder.desc(main.get("addedOn")))
.distinct(true);
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(queryParams.get("mobile"))) {
predicates.add(criteriaBuilder.and(criteriaBuilder.equal(main.get("mobile"), queryParams.get("mobile"))));
}
if (StringUtils.isNotBlank(queryParams.get("name"))) {
predicates.add(criteriaBuilder.and(criteriaBuilder.like(main.get("name"),
"%" + queryParams.get("name") + "%")));
}
if (StringUtils.isNotBlank(queryParams.get("email"))) {
predicates.add(criteriaBuilder.and(criteriaBuilder.equal(main.get("email"), queryParams.get("email"))));
}
criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()]));
log.info("TrainerDAO::getAllTrainersPaginatedForOwner Query created...");
TypedQuery<TrainerDTO> query = entityManager.createQuery(criteriaQuery);
query.setFirstResult(pageNumber - 1);
query.setMaxResults(pageSize);
return query.getResultList();
I am having two issues here :
How do I get all users which have a certain role? Suppose I need to find all users which have a Role with ROLE_ID = "ROLE_ADMIN".
In my pagination implementation, the last item in repeated on the next page. Suppose User1 was the last item on page 1, he is coming as first item on page 2 as well.
Please suggest on how to proceed further. All help would be appreciated.
Here is my way would be like this:
Issue 1:
You need to reach RoleEntity to check if the role_id is equal to "ROLE_ADMIN", so you need to fetch roles from RoleEntity first and get all the information there.
After you created main object:
Fetch<UserEntity, RoleEntity> fetchedRoles = main.fetch("roles", JoinType.LEFT);
You will append your condition to your predicates list;
predicates.add(criteriaBuilder.equal( fetchedRoles.get( "roleId" ), "ROLE_ADMIN"));
Issue 2:
I will try to share what I would do in this case to help you solve the issue.
Let's say you create the query here, in this method with pageable object, you want to return Page
private Page<Books> getUsersWithAdminRole(String... parameters, Pageable pageable){
//...
List<UserEntity> result = entityManager.createQuery(criteria).setFirstResult((int) pageable.getOffset()).setMaxResults(pageable.getPageSize()).getResultList();
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
Root<UserEntity> userCount = countQuery.from(UserEntity.class);
countQuery.select(criteriaBuilder.count(userCount)).where(criteriaBuilder.and(predicates.toArray(newPredicate[predicates.size()])));
Long count = entityManager.createQuery(countQuery).getSingleResult();
Page<UserEntity> userPage = new PageImpl<>(result, pageable, count);
return userPage;
}
I hope, it is helpful
I have two entities viz:
State
#Entity
#Table(name = "State")
public class StateEntity {
#Column(name = "id", length = 36, nullable = false, unique = true)
private String id;
#ManyToOne (fetch = FetchType.LAZY)
#JoinColumn(name = "InsurerId", nullable = false)
private InsurerEntity insurer;
#Column(name ="StateName", length = 50, nullable = false)
private String stateName;
//getters and setters
}
Insurer
#Entity
#Table(name = "Insurer")
public class InsurerEntity {
#Column(name = "InsurerId", length = 36, nullable = false, unique = true)
private String insurerId;
#Column(name = "InsurerName", length = 100, nullable = true)
private String insurerName;
#OneToMany(mappedBy = "state", fetch = FetchType.LAZY)
private List<StateEntity> stateEntityList;
//getters and setters
}
the insurer's id gets saved in state database and I want to retrieve it using hibernate query but I cant't seem to find the solution for that
How to write this query SELECT InsurerId FROM State; in Hibernate query using CriteriaBuilder, CriteriaQuery and Root..
If you want to select all Insurers's Ids for all states:
String selectionQuery = "SELECT s.insurer.insurerId FROM State s";
List<String> insurersIds = session.createQuery(selectionQuery).list();
If you want to select the Insurer's Id of a certain state:
String selectionQuery = "SELECT s.insurer.insurerId FROM State s WHERE s.id = :stateId";
String insurerId = (String) session.createQuery(selectionQuery).setParameter("stateId", stateId).getSingleResult(); //This should be placed in a try/catch block to handle org.hibernate.NonUniqueResultException
Edit:
You should update your Insurer entity as Prasad wrote in his answer.
for this you have to map both the class as in put #oneToMany annotation in class InsurerEntity as well
#OneToMany(fetch = FetchType.LAZY,mappedBy="StateEntity", cascade = CascadeType.ALL)
private List< StateEntity > StateEntitys;
and when you fetch states you will also get object of InsurerEntity in it from where you can access it with the getter
I have a User entity with a many-to-many relationship with a Role entity.
#Entity
#Table(name = "auth_user")
public class OAuthUser {
// #Autowired
// #Transient
// private PasswordEncoder passwordEncoder;
//
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "username")
private String userName;
#Column(name = "password")
#JsonIgnore
private String password;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
#Column(name = "is_enabled")
private boolean isEnabled;
/**
* Reference:
* https://github.com/nydiarra/springboot-jwt/blob/master/src/main/java/com/nouhoun/springboot/jwt/integration/domain/User.java
* Roles are being eagerly loaded here because they are a fairly small
* collection of items for this example.
*/
#ManyToMany(fetch = FetchType.EAGER)
#Fetch(value = FetchMode.SUBSELECT)
#JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id"))
private List<Role> roles;
#ManyToMany(fetch = FetchType.EAGER)
#Fetch(value = FetchMode.SUBSELECT)
#JoinTable(name = "user_properties", joinColumns = #JoinColumn(name = "AuthID", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "PropertyID", referencedColumnName = "id"))
private List<Property> properties;
I am using the Spring Data JPA repositories, and would to be able to create a custom #Query that returns a list of users based upon a particular role id.
#Query("SELECT u FROM auth_user as u WHERE u.isEnabled AND u.id IN"
+ " (SELECT r.user_id FROM user_role as r WHERE r.role_id = ?1)")
public List<OAuthUser> findByRole(int roleID);
The code above results in the error auth_user is not mapped. I do understand why I am getting the error; the framework is using the entity names (OAuthUser) rather than the table (auth_user) to perform the query. This would ordinarily not be a problem, except for there is no entity for user_role; it is simply a join table with two columns: 'user_id' and 'role_id'.
What is the appropriate way to achieve this?
Thanks.
The error says:
auth_user is not mapped
It refers to the auth_user used in the query like SELECT u FROM auth_user. It must be OAuthUser instead, in the query.
You are using the table name (auth_user) inside of you jpql #Query. You should use the class name OAuthUser instead:
#Query("SELECT u FROM OAuthUser u ...")
public List<OAuthUser> findByRole(int roleID);
If you want to use SQL instead of jpql, you need to use like this:
#Query(value = "SELECT * FROM auth_user ..." , nativeQuery=true)
public List<OAuthUser> findByRole(int roleID);
That way you could mention table name and columns.