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
Related
Consider the following method on a Spring Data JPA interface:
#Query("select distinct :columnName from Item i")
List<Item> findByName(#Param("columnName") String columnName);
I would like to use such a method for performing queries dynamically using different column names on the same entity. How can this be done?
You can't. You'll have to implement such a method by yourself. And you won't be able to use parameters: you'll have to use String concatenation or the criteria API. What you'll pass won't be a column name but a field/property name. And it won't return a List<Item>, since you only select one field.
You can use QueryDSL support built into Spring Data. See this tutorial to get started.
First of all you must implement custom Spring Data repository by adding interface:
public interface ItemCustomRepository {
List<Item> findBy(String columnName, String columnValue);
}
then you must extend your current Spring Data repository interface with newly created i.e.:
public interface ItemRepository extends JpaRepository<Item, Long>, ItemCustomRepository, QueryDslPredicateExecutor {
}
and then you must implement your interface using Query DSL dynamic expression feature (the name ItemRepositoryImpl is crucial - it will let you use original Spring Data repository implementation):
public class ItemRepositoryImpl implements ItemCustomRepository {
#Autowired
private ItemRepository itemRepository;
public List<Item> findBy(final String columnName, final String columnValue) {
Path<Item> item = Expressions.path(Item.class, "item");
Path<String> itemColumnName = Expressions.path(String.class, item, columnName);
Expression<String> itemValueExpression = Expressions.constant(columnValue);
BooleanExpression fieldEqualsExpression = Expressions.predicate(Ops.EQ, itemColumnName, itemValueExpression);
return itemRepository.findAll(fieldEqualsExpression);
}
}
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);
Here is my Repository
public interface NoteRepository extends JpaRepository<Note,Long> {
List<Note> findByContentContains(String content);
and my method in class NoteController which return me words with "e" in column Content
#GetMapping("/notesletter")
public List<String> getLetters(){
return noteRepository.findByContentContains("e")
.stream()
.map(note -> note.getContent())
.collect(Collectors.toList());
}
Please, help me to find a method which will return every words with letter "e",for example, from all columns.
I am working with Postman
Of course you can you native queries
#Query("select u from Note u where u.COL1 = ?1 and u.COL2 = ?1")
List<Note> findByContentContains(String content)
or use jpa feature as given below, Note findByLastnameOrFirstnameStartingWith is mentioned to understand easily, so replace your firstname,lastname as colu1name,col2name respectively.Refer here for more jpa method conventions`
public interface NoteRepository extends JpaRepository<Note,Long> {
List<Note> findByLastnameOrFirstnameStartingWith(String param1,String param2)
static List<Note> findByContentContains(String content){
findByLastnameOrFirstnameStartingWith(content,content);
}
}
You can try the or operation in the method name like below.
Or findByLastnameOrFirstname
https://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html
Other approaches are possible too.
If you know the native query or JPQL equivalent that returns the results checking all the columns of the entity.
Use of
#Query above the method in repository interface can take a JPQL or native query.
#NamedQuery annotation is also available if you know the query. This annotation to be used over the Entity class, name attribute is used to specify the accessing method name which returns the data, this can be used in repository interface.
I have a field in my mongodb called "name". I am using annotations in spring data to support querying. My question is, is there a way to support wildcard? i.e. If I have values for "name" called "Robert", "Roberto" "Ramano", I could support queries that allow me to pass say "R" to a function, and it will match on everything that starts with R? Right now I have to basically do an "exact spelling" of Robert, or any one of those names to get an exact match.
I know how to do wildcard search with mongodb directly, but am not sure how to do it in java with spring data. I have a model class representing my Student documents that I use annotations to describe how to query.
db.users.find({"name": /.*m.*/})
I don't know how to translate that into java as I want to pass in a variable. For example:
Pseudocode:
String myvar = "R";
db.users.find({/.*<variable here>*/})
The following is what I have on my "MongoRepository" implementation:
public interface UserRepository extends MongoRepository<UserId, String> {
{
#Query("{'name' : {$regex : ?0}}")
public List<Users> findByName(String username);
}
When I pass in the full name "Robert", then it is able to find "Robert". However, if I put "R", it does not find anything.
Did you try it with query method?
public interface UserRepository extends MongoRepository<UserId, String> {
{
public List<Users> findByNameLike(String username);
}
Why dont you use regex like you're trying to in the following manner :
public interface UserRepository extends MongoRepository<UserId, String> {
{
#Query("{'name' : {$regex : ?0}}")
public List<Users> findByName(String regexp);
}
and in your service form a query somewhat like this :
#Mock
UserRepository userRepository;
String queryInput = "^R.*$";
List<Users> users = userRepository.findByName(queryInput);
find more detailed answers in here in section 4.2
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