Spring JPA selecting from where clause - java

I am using Spring JPA to perform all database operations. However I don't know how to select specific rows (connected by simple WHERE clause) from a table in Spring JPA?
For example:
SELECT * FROM user where name=agrawalo AND email=abc#example.com
User Class:
#Entity
Class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String email;
// Getters and Setters
}
Repository:
public interface UserRepository extends JpaRepository<User, Integer> {
}

You don't need to write queries for such simple things if you are using spring-data-jpa. you can write a method name and spring-data will formulate a query based on your method name and get the results.
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByNameAndEmail(String name, String email)
}
Create a method like above and call the method with the required arguments.
If you don't want(not advisable) to use Optional, you can just use User as return type. In such case, if there are no entries matching your arguments then you would have null returned.

public interface UserRepository extends JpaRepository<User, Integer> {
public User findUserByNameAndEmail(String name,String email);
}
Implementation will be created on the fly.

I know I am very very late to this but I still want to provide another solution that one would like to use. This is particularly useful when you think the queries generated by method names do not serve the purpose that you want and you really want to write the native queries. To do that, you can actually use the #Query annotation in your repository and put your query inside it like below:
#Query(value = "SELECT * FROM user where name = ?1 AND email = ?2", nativeQuery = true)
List<User> getUserByNameAndEmail(String name, String email);
Here the #Query tells that the query provided in the value attribute needs to be executed and the nativeQuery attribute tells that it is a native sql query.
Notice that values for name and email are provided as ?1 and ?2 respectively which means these are placeholders and will be replaced by the parameters that getUserByNameAndEmail repository method will receive at runtime in variables name and email.

Simply you can declare below method in you repository interface, implementation will be taken care by Spring-data-jpa
User findByNameAndEmail(String name, String email);

Related

Mapping #Query with multiple column selection to an Java object in a #Repository - is it possible out of the box?

Is it possible to map the results of a Hibernate #Query like this (in a #Repository interface extending #JpaRepository):
#Query("select u.id, u.email, u.status from user u")
public SimpleUserDTO getAllUsersSimpleData();
directly to a Java object like this:
public class SimpleUserDTO {
private Long id;
private String email;
private String status;
}
What I know, is that doing something like this:
Query query = session.createQuery("select u.id, u.email, u.status from user u");
the result can be extracted to a List<Object[]>:
List<Object[]> users = (List<Object[]>) query.list();
But is it possible to map it directly to a List<SimpleUserDTO> without writing additional method that will map the values to SimpleUserDTO?
You have two options.
Option 1: Constructor Expression:
#Query("select new <insert_package_here>.SimpleUserDTO(u.id, u.email, u.status) from user u")
public List<SimpleUserDTO> getAllUsersSimpleData();
Option 2: Use Interface projection
Turn your DTO into an interface and you can use it without #Query annotation
public List<SimpleUserDTO> getAllUsersSimpleData();
Please find out more about projections and Spring Data JPA in the documentation:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections

Spring Boot query from controller

I have User class like this :
#Data
#Entity
public class User {
#Id #GeneratedValue Long userID;
String eMail;
String passwordHash;
}
And I have data like this :
[{"userID":1,"passwordHash":"asdasd","email":"admin#admin.com"},
{"userID":2,"passwordHash":"12345","email":"admin1asdasd#admin.com"}]
I have two method in my controller class, one - to get single user :
#GetMapping("/user/{id}")
User one(#PathVariable Long id) {
return repository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
Other method to retrieve all user :
#GetMapping("/user")
List<User> all() {
return repository.findAll();
}
In my browser, going to this address - http://localhost:8080/user , I can see these data. And if I goto http://localhost:8080/user/id I can get a specific value.
Now my question is how can access data like http://localhost:8080/user/email/passwordHash? I am quite sure that it is not possible, because I haven't stored data in that way.
As my main target is to verify login, I have already written a #Query in my repository interface. Here it is :
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.eMail = ?1 and u.passwordHash = ?2")
List<User> listByLoginCredential(String emailAddress,String passwordHash);
}
Can Anyone tell me how can I do this,use this method of this interface?
I think you can can achieve what you want by adding the following method to the controller class:
#GetMapping("/user/{emailAddress}/{passwordHash}")
List<User> byMailAndPassword(#PathVariable String emailAddress, #PathVariable String passwordHash) {
return repository.listByLoginCredential(emailAddress, passwordHash)
}
On the other hand you say that your main goal is to verify login, so it looks like you are doing authentication. If you have time you should look into doing it with spring security https://spring.io/guides/gs/securing-web/#initial
Maybe this help https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.
Or you can also create procedure in Database and call stored procedure with Spring boot.
Login is related to security so ideally you should create a separate post method and use the repository method. Always make sure to follow the best practice.
Spring security is something you can utilize for better authentication and authorization.

How to use createQuery with spring boot

Normally I use annotiations:#Query("SELECT c FROM Country c") with JpaRepositoryor predefined methods like findAll
but in my case I want to generate dynamic query.
String baseQuery =SELECT c FROM Country c`
if(age!=null)
baseQuery+="WHERE c.age=20"
I need to perform same query from code level like this:
Query q1 = em.createQuery("SELECT c FROM Country c");
but I dont use EntityManager in spring boot
How can I generate query from code level?
If you would like to create dynamic queries from code you can take advantage of Spring's JdbcTemplate. Using spring boot it is as simple as injecting JdbcOperations bean to your repository class (assuming you have provided spring-boot-starter-jdbc module to your project).
But remember! This solution uses SQL, not JPQL. That's why you have to use proper tables and columns names in queries and properly map result to objects (i.e. using RowMapper)
This simple example worked fine for me (with different entity, but in same manner - I've adapted it to your example):
#Repository
public class CountryRepository {
#Autowired
private JdbcOperations jdbcOperations;
private static String BASIC_QUERY = "SELECT * FROM COUNTRY";
public List<Country> selectCoutry(Long age){
String query = BASIC_QUERY;
if (age != null){
query += " WHERE AGE = ";
query += age.toString();
}
//let's pretend that Country has constructor Conutry(String name, int age)
return jdbcOperations.query(query, (rs, rowNum) ->
{ return new Country(rs.getString("NAME"), rs.getInt("AGE");}
);
};
}
Then in service or whatever you inject CountryRepository and call method.
Since you're using Spring Boot, you can use Spring Data to create queries in your repository:
#Repository
public interface CountryRepository extends JpaRepository<Country, Long> {
}
Not a 100% on syntax, but should be something similar.
Now you can autowire this class:
#Autowired
public CountryRepository countryRepo;
And all basic methods are already available to you like:
countryRepo.findOne(id);
countryRepo.find();
If you want to make more advanced queries, you can use Spring Data e.g.:
#Repository
public interface CountryRepository extends JpaRepository<Country, Long> {
public Country findByNameAndContinent(String name, String continent);
}
This is just an example (a stupid one) of course and assumes your Country class has the field names 'name' and 'continent' and both are strings. More is available here:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
Section 5.3 more specifically.
PS: Make sure your Country class has the #Entity annotation

Spring data repository's method to find by the field of a field

I've two entities, a user and a registered user.
A registered user has a field of type user. I would like to have a method in the spring data repository related to this registered user entity to search all registered users by the username of the user that is connected to the registered user.
So, this is the registered user entity with an associated user field:
#Entity
public class RegisteredUser implements Serializable {
...
#OneToOne
#JoinColumn(name = "USERNAME_FK")
private User user;
...
}
and this is a user with a username:
#Entity
public class User implements Serializable {
...
#Id
#Column(nullable = false)
protected String username;
...
}
Spring Data (at least 1.12.x version) uses PropertyPath#from method to extract path to a property for a predicate constructed from method name. According to sources it uses underscore as "field separator". So first variant is as follows
public interface RegisteredUserRepository extends CrudRepository<RegisteredUser,String> {
List<RegisteredUser> findRegisteredUserByUser_Username(String username);
}
There is also code which treat an uppercase char as field separator if whole field name is not found. So if you don't have a userUsername field in RegisteredUser second varian is
public interface RegisteredUserRepository extends CrudRepository<RegisteredUser,String> {
List<RegisteredUser> findRegisteredUserByUserUsername(String username);
}
You may also simply use a library like this one, which lets you build dynamic filters (supports logical operators, comparators, enums, dates, booleans, joins, functions, and much more): https://github.com/turkraft/spring-filter
You won't have to create any repository interface and you will be able to use the provided query builder in your client app directly.
Example query:
/search?filter= average(ratings) > 4.5 and brand.name in ('audi', 'land rover') and (year > 2018 or km < 50000) and color : 'white' and accidents is empty
Usage:
#GetMapping(value = "/search")
public List<Entity> search(#EntityFilter Specification<Entity> spec, Pageable page) {
return repo.findAll(spec, page);
}
Don't forget the dependency:
<dependency>
<groupId>com.turkraft</groupId>
<artifactId>spring-filter</artifactId>
<version>0.9.5</version>
</dependency>
You may also check rsql, although it's a bit outdated now https://github.com/jirutka/rsql-parser

Spring Data - Spring Repository: selecting distinct values for a class attribute

I have the following
#Entity
public class Restaurant{
#ManyToOne
private City c;
// more
}
#Entity
public class City{
private String name;
// more
}
I also have a repository
public interface RestaurantRepository extends JPARepository<Restaurant, Long> {
// something to put here
}
===EDIT====
I have the list of ALL cities, but only some of them are associated to restaurants.
I need to write a method in such respository to extract all cities that are referred by a Restaurant.
In SQL I would just do the following:
SELECT CITY.id, CITY.name FROM CITY WHERE ID NOT IN (SELECT DISTINCT(city_id) FROM RESTAURANT)
Is there a way to obtain the same result using the name conventions as of http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/jpa.repositories.html ?
Thanks.
As I do not see any support for the IS [NOT] EMPTY operator listed in Spring Data's documentation around query creation strategy, you can try manually defining a JPQL query:
public interface CityRepository extends JPARepository<City, Long> {
#Query(value="SELECT c FROM CITY c WHERE c.restaurants IS EMPTY")
List<City> findCitiesWithNoRestaurants();
}
which I'm guessing will translate to the native SQL you gave as an example.
Otherwise looks like you would need to find a list of cities with Restraunts and then pass that to a method which used the NotIn pattern. This will obviously be less performant than the above.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation

Categories

Resources