I was wondering if there was a way using JPA query (not sure what the word I'm looking for is sorry).
#Transactional
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastNameIgnoreCase(String lastName); //This is the format I am looking for
#Query("SELECT DISTINCT t.lastName FROM User t") //Don't want to have to use the #Query
List<String> findDistinctLastNames();
}
Hopefully that makes it more clear. But I am trying to perform that Query without having to use the #Query. It doesn't really affect anything having it there, I would just like it. Is that statement possible?
Spring Data JPA uses reflection to match method signatures to field names and operations so confirming you have the correct column name would be a good place to start, i.e. is it lastName or lastNames?
Otherwise, according to the Spring Data JPA documentation, the following should work correctly:
List<User> findDistinctByLastName(String lastName);
Are you getting a stack trace?
Related
I am new to JPA and Hibernate.
In one use case, I need to fetch all users from DB with associated email present in given email list.
To do this, I have written a custom JPA query as follows:
#Query("SELECT u from User u where u.email in :emailIds")
List<User> findUsersByEmailIds(#Param("emailIds") List<String> emailIdList);
But, I would like to know, is there any better way to do the same?
As commented by Vishnu, here is the explanation:
Assuming in your User entity you have a field like this:
private String email;
Then in your repository you can go like this:
List<User> findByEmailIn(List<String> emailIdList);
The important key thing to notice here is the Capital E in findByEmailIn while in your entity this field was email (small e). This way you can eliminate the #Query statement completely.
I am developing Spring Boot + Spring Data JPA + Postgres + Lombok example. In this example, I want to fetch all student firstName is ASC order and whose status in Active.
I developed below query, which works fine, but I dont see a way to also use status=Active here in JpaRepository query.
NOTE: In my case, status field is Enum in Java.
Is there any way if we can do the same ? I know I can fetch all students and then using streams can easily filter, but using JpaRepository query, is there any way?
List<Student> students = studentRepository.findAll(new Sort(Sort.Direction.ASC, "studentName"));
In your StudentRepository interface, that extends Repository / JpaRepository you can add a method signature like that:
public interface StudentRepository extends ....{
List<Student> findAllByStatusOrderByStudentNameAsc(String status);
}
Just put the following method signature in your repository and call it where you need with argument 'Active'.
List<Student> findAllByStatusOrderByStudentNameAsc(String status);
I just got started with Spring JPA and I am reviewing code written by my coworker.
I see that he has been using the following code to find a Login object using username:
public interface LoginDao extends JpaRepository<Login, Long> {
#Query("SELECT u FROM Login u WHERE LOWER(u.username) = LOWER(:username)")
Login findByUsername(#Param("username") String username);
}
Cant he just create a method like this:
#GET
#Path("{username}")
public Login getOne(#PathParam("username") String username) {
Login login = loginDao.findOne(username);
if (login == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
} else {
return login;
}
}
What are the fundamental advantages of using #Query rather than writing a method approach. Or am I plain wrong and both have different purposes.
I personally dont want to write queries inside the code. I think mixing java with sql queries can make code look uglier.
Our stack is java, JPA, Jersey, JAX-RS, Postgreql, Spring Boot, Hibernate
Regards
First, This is not an SQL query, this is a JPQL one. It would be a native SQL query if the nativeQuery attribute was set to true, which is not the case by default.
It is perfectly fine to create queries with JPQL, you will be able to switch from Hibernate to Eclipse Link or another JPA implementation without issues. You should also be able to switch from Postgres to MySQL, SQL Server...
You have to start to worry if your coworker creates queries with #Query(nativeQuery = true, value = "..."), otherwise it looks fine to me.
Second, when you look to your repository declaration, you can see that the ID field for your Login entity is of type Long. That means the loginDao.findOne(..) method wants a Long parameter. Probably a surrogate key which is not username.
This is why your coworker created this new method: to find a Login row by something else than the Long surrogate key. (Here by username which is most likely a business key, but I do not know your application.)
Just for your information: Spring automatically creates queries with the signature of your repository methods (derived queries). For example:
public interface LoginDao extends JpaRepository<Login, Long> {
Login findByUsername(String username);
}
Spring JPA will automatically create a query looking for a field named username and create a WHERE clause with it.
Notice that it is not the same than your coworker query because it will not use the LOWER function.
Some anchors in the JPA documentation about those derived queries:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords
Another thing about your title:
"Why need #Query when I can write a method in Spring JPA"
Well this #Query writes a method in Spring JPA. :^)
JPARepository has come up with some of the Supported keywords which will write the queries themselves based on your entity.
If we are looking something out of box from what JPARepository provides #Query is useful like - Joining multiple queries, writing native queries etc.
From your code snippet both would do the same
For more info you can refer - https://docs.spring.io/spring-data/jpa/docs/1.4.2.RELEASE/reference/html/jpa.repositories.html
In Spring Data is it possible to turn off Query Generation from method names?
Given the interface
public interface UserRepository extends Repository<User, Long> {
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
I would want spring security to produce an error saying that generating queries from method names has been turned off please use the explicitly #Query annotation like so.
public interface UserRepository extends Repository<User, Long> {
#Query("select u from User u where u.emailAddress = ?1 and u.lastname = ?2")
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
I want to turn off the the automatic query generation because I think it is easier to read the query and know what is going on rather than reading the method name and translating to what is the query that Spring data will generate, also on a large team with lots of developers some who might not yet be familiar with spring data #Query is a lot more readable?
How to turn off Query creation from method names in Spring JPA?
You can specify the query-lookup-strategy on the repositories tag in the configuration.
<repositories query-lookup-strategy="use-declared-query"/>
See the documentation
User.java
#Entity
#NamedQuery(name="User.findByEmailAddressAndLastName",
query="select u from User u where u.emailAddress = ?1 and u.lastname = ?2")
public User{
}
UserRepository.java
public interface UserRepository extends Repository<User, Long> {
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
How Spring handles this is called the Query Lookup Strategy. Queries can be resolved by method names (CREATE), by manual queries (USE_DECLARED_QUERY), or both (CREATE_IF_NOT_FOUND) which defaults to method names if no manual query is found. USE_DECLARED_QUERY would give you the desired functionality, warning you if no manual query is specified.
As Kevin answered, this can be configured in xml. But as a more modern option, you can specify the lookup strategy when configuring your repository in a Java Config class with queryLookupStrategy parameter in the #Enable{store}Repositories annotation.
For example, to force manual queries, you could use the following:
#EnableJpaRepositories(queryLookupStrategy=QueryLookupStrategy.Key.USE_DECLARED_QUERY)
public class MyDatabaseConfig {
...
}
More info here
https://docs.spring.io/spring-data/jpa/docs/2.0.7.RELEASE/reference/html/#repositories.query-methods.query-lookup-strategies
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/query/QueryLookupStrategy.Key.html?is-external=true
I need to set a table name dynamically so that I use query.setText(tname,abc)
e.g: select a.name from :tname where a.id = '2'
I used setText() because when I use setString() it says "tname is a invalid parameter" because I assume that Hibernate adds '' when setting string parameters.
But even setText() does not help and gives the same exception.
How can I set the table name dynamically?
Reply to PSR:
So you mean replace table name as a java string replacement. But then we can not take support of sql injections prevention etc from hibernate right? Also How we bind parameters in hibernate in a situation where like statement,
Eg: name like "%:name%"
This also gives me Illegal argument exception: Parameter does not exist as a named parameter when i try to bind it using query.setString(name,"def");
Hibernate will not do this for you, because it works with PreparedStatements, and you can't prepare a statement where the table being queried isn't known yet.
I don't see why you would be exposing table names to end users, so preventing SQL injection doing a regular string substitution should be easy. You use some sort of business logic to determine the correct table from a list that only you know. The table name isn't coming from user input at all.
Depending on your choice of RDBMS, you may find a discriminator column, or table inheritance with partitioning to be a better way of handling a situation where identical queries are made against different tables.
It is not possible to set table name dynamically.You can set dynamically column names.it is not possible to set table name
try like this
select a.name from '+table name+'where a.id = '2'
In my opinion, There are 2 ways to resolve this issue:
1- If you are using Spring and Hibernate together, you could use SpEL and it would be like #{#entityName} as it is described here
#Entity
public class User {
#Id
#GeneratedValue
Long id;
String lastname;
}
public interface UserRepository extends JpaRepository<User,Long> {
#Query("select u from #{#entityName} u where u.lastname = ?1")
List<User> findByLastname(String lastname);
}
2-You could use CriteriaBuilder like
CriteriaQuery<YourEntity> cr = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cr.from(YourEntity.class);
cr.select(root);
I copied the source codes from the provided links and they are described there much better