Combine parameters and hardcoded clauses in Spring JPA #Query - spring

I have a user repository in the application which works nicely for cases like this one:
#Query(" FROM UserEntity ue WHERE ue.site.id = :site_id
and ue.name = :username")
User findByUsername(#Param("site_id") String siteId,
#Param("username") String userName);
There is now a new option in one of the user fields, which should prevent the user to appear anywhere in the application. So instead of modifying the whole application, I've decided to modify just the queries in repositories with hardcoded clause like this:
#Query(" FROM UserEntity ue WHERE ue.site.id = :site_id
and ue.name = :username and ue.state != 'Disabled'")
User findByUsername(#Param("site_id") String siteId,
#Param("username") String userName);
(The changed part is and ue.state != 'Disabled')
The problem is, that such query doesn't return anything no matter what the value of state is.
I've also tried ue.state not like 'Disabled', but with the same result.
I've seen a lot of examples of using #Query, but didn't find any with hardcoded clauses. Is that even possible?

Yes you can pass the hardcoded values without changing the method signature.
JPA repository
#Query(" FROM Users ue WHERE ue.userLogin = :userLogin and ue.userName != 'admin'")
public Users cehckeme(#Param("userLogin") String userLogin);
Test Code
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"spring_model.xml");
usersRepository = (UsersRepository) ctx.getBean("usersRepository");
System.out.println(usersRepository.cehckeme("pthakre").getUserLogin());
Genrated query
Hibernate:
select
*
from
( select
users0_.USER_ID as USER1_2_,
users0_.USER_LOGIN as USER2_2_,
users0_.USER_NAME as USER3_2_,
users0_.USER_PASSWORD as USER4_2_
from
MED_USERS users0_
where
users0_.USER_LOGIN=?
and users0_.USER_NAME<>'admin' )
where
rownum <= ?

Related

How to fetch list of objects with same phone number

I have an entity for driving_info with lot of fields but one of them is a phone number ( from which was ordered ).
What I am trying to do is to fetch all drives that were ordered from that number. But when I try to pass the int of phoneNumber I get
query did not return a unique result: 5; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 5
org.springframework.dao.IncorrectResultSizeDataAccessException: query did not return a unique result: 5; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 5
I actually want the list of results so that I can get a response of list of all drives that were ordered from that phone number.
My controller method is
#GetMapping("/users/{phone}")
public List<User> getUserByPhone(#PathVariable int phone) {
List<User> users= userService.findByPhone(phone);
if(users == null) {
throw new RuntimeException("User not found with "+phone+" phone number");
}
return users;
}
And my DAO is
#Override
#Transactional
public List<User> findByPhone(int phone) {
Session currentSession = entityManager.unwrap(Session.class);
Query<User> theQuery = currentSession.createQuery("from User where phone=:phone",User.class);
List<User> users = theQuery.getResultList();
return users;
}
Try to correct your query in this way:
List<User> users = currentSession.createQuery(
"select u from User u where u.phone = :phone",
User.class
).setParameter( "phone", phone )
.getResultList();
Please note that as it's stated in the documentation:
Even though HQL does not require the presence of a select_clause, it is generally good practice to include one. For simple queries the intent is clear and so the intended result of the select_clause is easy to infer. But on more complex queries that is not always the case.
It is usually better to explicitly specify intent. Hibernate does not actually enforce that a select_clause be present even when parsing JPQL queries, however, applications interested in JPA portability should take heed of this.
You need to call theQuery.list() instead.

Why can JPQLs modifying queries only return void or int?

When i want to modify the database via JPQL i have to mark the query as Transactional and Modiyfing. If i do so, the return type of the method representing the query has to be either void or int(representing the number of edited rows i think). Why are only the two return types allowed? If i do a HTTP-PUT request and update the object with an own JPQL query, i would like to return the updated object again. Whats the best way to do it if the return type of the query has to be void or int? Do i have to do a seperate query/request again which selects the object after it was updated?
EDIT:
Thats how i call the query:
if (inactivityListDTO.getProjectIds().size() > 0) {
projectRepository.updateProjectsIsArchivedByProjectIds(inactivityListDTO.getProjectIds(), inactivityListDTO.getIsArchived());
}
Thats the query:
#Transactional
#Modifying
#Query("UPDATE Project project SET project.isArchived = :isArchived,
project.archivedDate = current_date " +
"WHERE project.id IN :ids")
void updateProjectsIsArchivedByProjectIds(#Param("ids") List<Long> ids, #Param("isArchived") boolean isArchived);
Because it finally boils down to execute a standard UPDATE SQL in the DB , and the UPDATE in standard SQL only returns the number of records being updated and does not return a result set.
And yes , if you need get a record 's value after update , you have to query it again. Alternatively , you should consider using a JPA way to update a record , which first query the object , then update it by changing its state . Something like below (Assume you are using spring #Transactional to manage the transactional boundary):
#Transactional
public void changeEmployeeSalary(Integer employeeId , Integer salary){
Employee employee = entityManager.find(Employee.class , employeeId);
employee.setSalary(salary);
}
In this way , you do not need to query the record again after it is updated and you also do not need to manually write a UPDATE SQL.

Retrieve generated ID using MyBatis Annotation Spring Boot

I am trying to learn MyBatis. How to do I get the auto-generated ID after I have inserted a statement using the #InsertAnnotation.
Example of my code:
#Insert("INSERT INTO user(name, mobile, password) VALUES(#{name}, #{mobile}, #{password})")
#SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", before = false, resultType = Long.class)
Long insertUser(User user);
I want to get the generated id as the return from the insert method.
#SelectKey is for legacy drivers.
For recent drivers, you should use useGeneratedKeys.
We have an FAQ entry explaining how to do it with XML mapper.
With annotation, it would look as follows.
#Insert("INSERT INTO user(name, mobile, password) VALUES(#{name}, #{mobile}, #{password})")
#Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);
Note that #Insert method returns the number of updated rows, not the generated key.
The generated key is assigned to the property of the parameter specified by keyProperty i.e. User.id in your case.
For some databases, you might need to specify keyColumn as well.
If it didn't work, please add versions of DB, driver and MyBatis to the question.
#Select("insert into security.users (name,email,password) values(#{user.name}, #{user.email}, #{user.password}) returning id")
#Result(column = "id")
this worked me. but i try a many time with #INSERT annotation not worked;

Query to check if the record exists in Spring Jdbc Template

I am fairly new to spring ,I am looking to check if a certain email id exists in database or not , using Spring Jdbc Template ,I looked here but could'nt find the proper answer .I am looking something like ,SELECT count(*) from table where email=?
Any help will be appreciated.
You can do something as below if you are using jdbctemplate and new version of spring
private boolean isEmailIdExists(String email) {
String sql = "SELECT count(*) FROM table WHERE email = ?";
int count = jdbcTemplate.queryForObject(sql, new Object[] { email }, Integer.class);
return count > 0;
}
queryForObject method of jdbcTemplate accepts the sql query as the first parameter, second argument is an array of objects for the sql query place holders and the third argument is the expected return value from the sql query.
In this case we only have one place holder and hence I gave the second argument as new Object[] { email } and the result we are expecting is a count which is a Integer and hence I gave it as Integer.class
I kind of got this answer from https://www.mkyong.com/spring/jdbctemplate-queryforint-is-deprecated/
You can go through it if you are interested.
private boolean isEmailIdExists(String email) {
return jdbcTemplate.queryForObject("SELECT EXISTS(SELECT FROM table WHERE email = ?)", Boolean.class, email);
}
http://www.postgresqltutorial.com/postgresql-exists/

Issue with writing named sql query with hibernate

I am trying to access database FK using named SQL query with Hibernate, the idea is to query a customer table which contains name, and companyId,etc. CompanyId is the FK for a commpany table. The query I wrote is as follows:
#NamedNativeQuery(name="getcustomer", query="Select CUSTOMER.* from CUSTOMER,COMPANY where CUSTOMER_FIRST_NAME = (?1) and CUSTOMER_LAST_NAME= (?2) and CUSTOMER_COMPANY_ID_FK = (?3) ",resultClass=Customer.class)
The issue I am currently having as follow:
Exception in thread "main" org.hibernate.QueryParameterException:
Position beyond number of declared ordinal parameters. Remember that
ordinal parameters are 1-based! Position: 2 at
org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterDescriptor(ParameterMetadata.java:89)
at
org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterExpectedType(ParameterMetadata.java:109)
at
org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:507)
at
org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:479)
at
com.comresource.scrapmetalapp.DAOImpl.CustomerDAOImpl.searchCustomer(CustomerDAOImpl.java:61)
at
com.comresource.scrapmetalapp.ServiceImpl.CustomerServiceImpl.searchCustomer(CustomerServiceImpl.java:39)
at com.comresource.scrapmetalapp.Config.Run.main(Run.java:57)
My DAO implementation is like this:
#Override
public Customer searchCustomer(String fName, String lName, Integer company) {
Session session = sessionFactory.openSession();
return (Customer) session.getNamedQuery("getcustomer").setParameter(1, fName)
.setParameter(2, lName)
.setParameter(3, company)
.uniqueResult();
}
What is the issue here?
For this, I would need to see how you are associating the mapping in your model class, but the query should go like this.
public Customer getMeThatCustomer(String param1, String param2, int foreignkey){
session = getCurrentSession();
org.hibernate.Query query = session.createQuery("From Customer as c where c.name=:param1 and c.lastname=:param2 and c.company.companyid=:foreignkey");
//Note the last parameter, where I have mentioned c.company, in place of
company, there should be the foregin key association and then the primary key in java class.
query.setParameter("param1",param1);
query.setP...er("param2",param2);
quer.....("companyid",companyid);
return (Customer) query.uniqueResult();
}
So, try it out, let me know if there is any problem

Resources