Spring data jpa query name - spring

I would like to use the built in query creation from method names, for example:
public Person findByFirstName(String firstName);
But I want to mark specific queries "for update" meaning to use:
public Person findByFirstNameForUpdate(String firstName);
Is there a way to make it work? I know I can create a new repository "PersonRepositoryForUpdate" but can I use the same repository?

You can add the #Query annotation above the method and use any query and any name for the method.
#Query("select ...")
public Person findGiveAnyName(String firstName);
The query can be written in JPQL or SQL.

Related

How to pass pageable for native query?

I was doing a project and there i had a requirement of using pageable object and recieved page object from JPA.
Does anyone have any idea on how to use this?
#Repository
public interface CustomerRepository extends JpaRepository<Customer,Long>{
#Query("SELECT * FROM WHERE name=?1 AND surname=?2 ", nativeQuery = true)
List<Customer> findAllByNameAndSurname(String name,String surname);
}
I want a page List for result fetch from this query.
Spring Data JPA and native queries with pagination is not supported in Spring. According to documentation , Spring Data JPA repositories can be used with native queries and pagination. But, in real life Spring Data JPA (1.10.2.RELEASE) requires some additional fix.
You have to use this if you want pagination support.
List<Customer> customers = customerRepository.findAllByNameAndSurname(name,username);
PagedListHolder<Customer> pages = new PagedListHolder(customers);
pages.setPage(currentPageNumber); //set current page number
pages.setPageSize(pageSize); // set the size of page
pages.getPageList(); // return the list of items(or in your case List<Customer> ) of current page
Try this:
#Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Page<Customer> findAllByNameEqualsAndSurnameEquals(String name, String surname, Pageable pageable);
}
I am pretty sure JpaRepository can handle your Pageable parameter.
Also, method name has to be as I mentioned as spring creates queries based on method name (uses reflection).
If you really need to execute NATIVE QUERY you will have to find other solution but I do not recommend the one provided by Dasari Swaroop Kumar as it just queries all objects from database and then kinda filters it in memory.
Also to that native query solution - you can extend your method definition to additional 2 parameters for page and pageSize and append them to your native query and leave repository to return plain List and then create PageImpl object in the layer that calls your CustomerRepository object.

How to get the specific property value from .properties file in Spring Data Repository interface method #Query

I am able to get the property value in Spring classes like below:
#Value("${database.name}")
private String databaseName;
I have to execute a native query by joining different tables which are in different databases.
#Query(value="select t1.* FROM db1.table1 t1 INNER JOIN db2.table2 t2 ON t2.t1_id1 = t1.id1")
Instead of hard coding database names i.e., db1 and db2 here, I have to get them from properties file.
how to get the property value inside the #Query annotation in Spring Data JPA Repository ?
I don't know if it is possible, but if not, you can consider this approach:
Instead of using properties in Repository's #Query directly, you can use params in the query but when you call the actual method - you can provide values from .properties.
Imagine you have simple repository:
public interface UserRepository extends JpaRepository<User, Long> {
// query with param
#Query("select u from User u where u.lastname = :lastname")
User findByLastname(#Param("lastname") String lastname);
}
Then, let's say you have some Service or Controller where you need to use your Repository - you can inject properties there and pass them to your method:
#Service
public class UserService {
// this comes from .properties
#Value("${user.lastName}")
private String userLastName;
#Autowired
private UserRepository userRepository;
public User getUser() {
// you pass it as param to the repo method which
// injects it into query
return userRepository.findByLastname(userLastName);
}
}
This is just an example. But I believe it may be useful.
Happy hacking :)

Spring data jpa query to return with multiple properties

I have to fetch Users by id and state.The method takes a set of usersIds as input.
I need a jpa query like below:
public Set<Users> fetchUsersByIdsContainingStateId(Set<Integer> userIds, Integer stateId)
Is there a query like the above in Spring Data JPA or I need to resort to named query
you can use spring data query:
public interface UserRepository extends CrudRepository<User, Long> {
Set<User> findUserByIdInAndStageId(Set<Long> userIds , Long stageId);
#Query("select u from User u where u.id in (:userIds) and u.stage.id=:stageId")
Set<User> findUserByUserIdsAndStageId(#Param("userIds") Set<Long> userIds , #Param("stageId") Long stageId);
}
for method findUserByIdInAndStageId spring data generates something
like
-- whereuser0_.id in (? , ? , ?...)) and stage1_.id=?
method findUserByUserIdsAndStageId do the same as findUserByIdInAndStageId , but in Query annotation you should write your query.
second search method findUserByUserIdsAndStageId named just for example , but I'll change it into something more readable like findUserWithStage(......)
PC don't use for domain model plural name like Users , use singular User

SpringData findAll is processing all database tables and not the one requested

I am new to SpringData and I am not getting what is happening here. I have created an Interface that extends PagingAndSortingRepository and overrided the findAll() method like this:
#Override
#Query
List<MyEntity> findAll();
I am calling this method in my service, but it is making my app to throw an exception Caused by: java.lang.StackOverflowError because that method is reading through the entire database, not only from MyEntitytable in database. Any idea?
Apparently the problem is in the configuration of EclipseLink. In persistence.xml I added this row <shared-cache-mode>NONE</shared-cache-mode> and now it works as it should.
no need to override getall() method.in your service autowired that dao or repository class and using this you can directly call the findall() method.
in the case you want to write your custom method apart from what given by spring data jpa then we use the #Query to write custom query.
No Need to Override. What i have done is i have created a repository i.e
FavoriteRepository which is extending JpaRepository and i have mentioned the
dbmodel name (Favorite)
like this JpaRepository<Favorite, Long> // Here Favorite is my model name
and Long is the type of primary key mentioned in db model Favorite as #Id
#Repository
public interface FavoriteRepository extends JpaRepository<Favorite, Long>{
}
Now you can use method findOne or findAll. As these methods are present in
Jparepository.Hope so it will help
If you want to add new method then use #Query with JpQL
#Query(value = "select f from Favorite f where f.userId=:userId ")
public List<Favorite> getFavoritesForUser(#Param("userId") String userId);

Spring Data: "delete by" is supported?

I am using Spring JPA for database access. I am able to find examples such as findByName and countByName, for which I dont have to write any method implementation. I am hoping to find examples for delete a group of records based on some condition.
Does Spring JPA support deleteByName-like delete? Any pointer is appreciated.
Regards and thanks.
Deprecated answer (Spring Data JPA <=1.6.x):
#Modifying annotation to the rescue. You will need to provide your custom SQL behaviour though.
public interface UserRepository extends JpaRepository<User, Long> {
#Modifying
#Query("delete from User u where u.firstName = ?1")
void deleteUsersByFirstName(String firstName);
}
Update:
In modern versions of Spring Data JPA (>=1.7.x) query derivation for delete, remove and count operations is accessible.
public interface UserRepository extends CrudRepository<User, Long> {
Long countByFirstName(String firstName);
Long deleteByFirstName(String firstName);
List<User> removeByFirstName(String firstName);
}
Derivation of delete queries using given method name is supported starting with version 1.6.0.RC1 of Spring Data JPA. The keywords remove and delete are supported. As return value one can choose between the number or a list of removed entities.
Long removeByLastname(String lastname);
List<User> deleteByLastname(String lastname);
2 ways:-
1st one Custom Query
#Modifying
#Query("delete from User where firstName = :firstName")
void deleteUsersByFirstName(#Param("firstName") String firstName);
2nd one JPA Query by method
List<User> deleteByLastname(String lastname);
When you go with query by method (2nd way) it will first do a get call
select * from user where last_name = :firstName
Then it will load it in a List
Then it will call delete id one by one
delete from user where id = 18
delete from user where id = 19
First fetch the list of object, then for loop to delete id one by one
But, the 1st option (custom query),
It's just a single query
It will delete wherever the value exists.
Since in 2nd option it is making multiple DB query, try to use the first option.
Go through this link too https://www.baeldung.com/spring-data-jpa-deleteby
If you take a look at the source code of Spring Data JPA, and particularly the PartTreeJpaQuery class, you will see that is tries to instantiate PartTree.
Inside that class the following regular expression
private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^(find|read|get|count|query)(\\p{Lu}.*?)??By")
should indicate what is allowed and what's not.
Of course if you try to add such a method you will actually see that is does not work and you get the full stacktrace.
I should note that I was using looking at version 1.5.0.RELEASE of Spring Data JPA
If you will use pre defined delete methods as directly provided by spring JPA then below two queries will be execute by the framework.
First collect data(like id and other column) using by execute select query with delete query where clause.
then after getting resultSet of first query, second delete queries will be execute for all id(one by one)
Note : This is not optimized way for your application because many queries will be execute for single MYSQL delete query.
This is another optimized way for delete query code because only one delete query will execute by using below customized methods.
#NamedNativeQueries({
#NamedNativeQuery(name = "Abc.deleteByCreatedTimeBetween",
query = "DELETE FROM abc WHERE create_time BETWEEN ?1 AND ?2")
,
#NamedNativeQuery(name = "Abc.getByMaxId",
query = "SELECT max(id) from abc")
})
#Entity
public class Abc implements Serializable {
}
#Repository
public interface AbcRepository extends CrudRepository {
int getByMaxId();
#Transactional
#Modifying
void deleteByCreatedTimeBetween(String startDate, String endDate);
}
It works just
import org.springframework.transaction.annotation.Transactional;
#Transactional
Long removeAddressByCity(String city);
Yes , deleteBy method is supported
To use it you need to annotate method with #Transactional
here follows my 2 cents. You can also use native queries, like:
#Modifying
#Query(value="delete from rreo r where r.cod_ibge = ?1 and r.exercicio= ?2", nativeQuery = true)
void deleteByParameters(Integer codIbge, Integer exercicio);
#Query(value = "delete from addresses u where u.ADDRESS_ID LIKE %:addressId%", nativeQuery = true)
void deleteAddressByAddressId(#Param("addressId") String addressId);

Resources