How do I make findByIn search using IgnoreCase of <Field>?
I tried to use findByNameIgnoreCaseIn and findByNameInIgnoreCase with no result.
DB is Postgresql.
#Repository
public interface UserRepository {
List<User> findByNameIgnoreCaseIn(List<String> userNames);
}
Try something like this:
List<User> findByNameInIgnoreCase(List<String> userNames);
As I understood IgnoreCase is not supported with In key, so I changed code this way:
#Repository
public interface UserRepository {
#Query("select user from SysUser user where upper(name) in :userNames")
List<SysUser> findByNameIgnoreCaseIn(#Param("userNames") List<String> userNames);
}
and previously upper case userNames values.
Related
I have a springboot application where I am saving a list with my Meeting Entity. I can save my entities all at once, but I want to check before each save if one entity inside my list already exists inside my Db and then just save the ones which are not inside. But I am kinda stuck and do not know how to do it. Could someone look at my code and give me an advice?
MeetingController:
#PostMapping("/")
public void saveMeeting(#RequestBody List<Meeting> meeting){
List<Meeting> exist =
meetingService.findAllMeetingsWithName(meeting.stream().map(m -> m.getMeetingName()).collect(Collectors.toList()));
meeting.removeAll(exist);
meetingService.saveMeeting(meeting);
}
MeetingService:
public void saveMeeting(List<Meeting> meeting){
meetingRepository.saveAll(meeting);
}
Repository:
#Repository
public interface MeetingRepository extends JpaRepository<Meeting, Long> {
}
This is the functionality that you want
#Transactional
public void saveMeeting(List<Meeting> meeting){
List<Meeting> alreadyExist = meetingRepository.findByMeetingNameIn(meeting.stream().map(m -> m.getMeetingName()).collect(Collectors.toList());
meeting.removeAll(alreadyExist);
meetingRepository.saveAll(meeting);
}
and then just define that repository method
#Repository
public interface MeetingRepository extends JpaRepository<Meeting, Long> {
List<Meeting> findByMeetingNameIn (List<String> meetingNames);
}
Remember to override equals and hashcode in Meeting entity to consider the id field.
You can check whether your meetings are in the DB. Try this.
List<Meeting> findByValueIn(List<Meeting> values);
Since you already are planning to use JpaRepository, take advantage of the #Query and batch queries
#Repository
//custom query using IN
public interface MeetingRepository extends JpaRepository<Meeting, Long>
{
#Query("SELECT m from MEETING m where m.name IN (:names)")
public List<Meetings> findAllMeetingWithNames(List<String> meetings)
}
#Service
class MeetingService{
private MeetingRepository meetingRepository;
...
//other code....
#Autowired
public MeetingService(MeetingRepository meetingRepository){
this.meetingRepository = meetingRepository;
}
public void saveAllMeetings(List<Meeting> meetings){
//call repository custom query here
names = meetings.stream()
.map((m) -> m.name)
.collect(Collectors.toList());
List<Meeting> existingMeetings = meetingRepository.findAllMeetingWithNames(names);
//delete using a single query
meetingRepository.deleteAllInBatch(existingMeetings);
meetingRepository.saveAllAndFlush(meetings);
}
.....
}
In Spring Data JPA we can define a repository interface extending Repository and write a custom method.
If this method follows special syntax, Spring Data will generate the method body automatically.
For example (from the documentation):
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLastname(String lastname);
}
Is there a way to customize the method generation code to introduce new keywords into the syntax?
For example:
Person findExactlyOneById(Long id);
This method would either return the entity or throw a custom exception.
I know I can customize specific repositories as well as the base repository and achieve the effect from the above example, but I'm specifically asking for the automatic method of body generation.
Is there an extension point designed in the framework? Or is the only option to change the source code?
In your case, you can always use CrudRepository.findById(Long id) or JpaRepository.getOne(Long id).
I would suggest inheriting from the JpaRepository class because all types of repositories are included.
You can set nativeQuery = true in the #Query annotation from a Repository class like this:
public static final String FIND_PROJECTS = "SELECT projectId, projectName FROM projects";
#Query(value = FIND_PROJECTS, nativeQuery = true)
public List<Object[]> findProjects();
It's probably worth looking at the Spring data docs as well.
Some more example
1.
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
I am using Spring Data JPA and I want to encapsulate a method which performs specific SQL. I do it in the following matter:
#Component
public interface UserRepository extends CrudRepository<User, String> {
#Query(
value = "delete from User u where u.alias = :alias",
nativeQuery = true
)
void deleteUserByAlias(#Param("alias") String alias);
}
However, I got the following message as the result:
{
"timestamp": "2018-12-11T15:54:54.627+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet",
"path": "/user/delete"
}
So where is the problem?
If your method is already Transactional , then please use transactional on repository method also
#Component
public interface UserRepository extends CrudRepository<User, String> {
#Query(
value = "delete from User u where u.alias = :alias",
nativeQuery = true
)
#Modifying
#Transactional
void deleteUserByAlias(#Param("alias") String alias);
}
#Repository
#Transactional
interface OrderRepository: JpaRepository<Order, OrderIdentity>{
#Query("SELECT * FROM orders WHERE id=:id",nativeQuery = true)
fun findBy(#Param("id") id: String): List<OrderEvent>
#Modifying
#Query("DELETE FROM orders WHERE id=:id", nativeQuery = true)
fun deleteFor(#Param("id") id: String)
}
By using #Modifying on method and #Transactional on Repository error will be resolved.
your class should be like this:
#Component
public interface UserRepository extends CrudRepository<User, String> {
#Query(
value = "delete from User u where u.alias = :alias",
nativeQuery = true
)
#Modifying
void deleteUserByAlias(#Param("alias") String alias);
}
As you can see I am using #Modifying, for more information take a look to this https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.modifying-queries
Not answer my question directly, but found a workaround to remove record based on other attribute but not ID.
According to answer from this thread,
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 deleteByLastname(String lastname);
I can write
#Transactional
void deleteByAlias(String alias);
at UserRepository to achieve the goal.
I won't accept this answer and open for any further contribution.
Check the param you are passing is not null. it worked for me.
I have an entity that hold some logic data :
#Entity
public class Person {
private Long id.
private String name;
private int age;
private String address;
...
}
I create my Spring data interface
#Repository
public interface CardInventoryRepository extends JpaRepository<Person , Long> {
}
My purpose is to create a dynamic query based on the exist values of my entity for example
if the name is null the query is :
select * from Person p Where p.age=12 AND p.address="adress.."
When the address is null the query should be :
select * from Person p Where p.age=12 AND p.name="ALI"
I want to extract data using only the non empty fields ?
is there any solution suing spring data for building dynamic queries ?
Thanks in advance
Based on Spring doc https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#query-by-example
Query by Example (QBE) is a user-friendly querying technique with a
simple interface. It allows dynamic query creation and does not
require you to write queries that contain field names. In fact, Query
by Example does not require you to write queries by using
store-specific query languages at all.
DEFINITION:
An Example takes a data object (usually the entity object or a sub-type of it) and a specification how to match properties. You can use Query by Example with JPA
Repositories.
To do so, let your repository interface extend QueryByExampleExecutor<T>, for example:
public interface PersonRepository extends CrudRepository<Person, String>, QueryByExampleExecutor<Person> {
}
Here are the available methods in QueryByExampleExecutor :
public interface QueryByExampleExecutor<T> {
<S extends T> S findOne(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example);
// … more functionality omitted.
}
USAGES:
Example<Person> example = Example.of(new Person("Jon", "Snow"));
repo.findAll(example);
ExampleMatcher matcher = ExampleMatcher.matching().
.withMatcher("firstname", endsWith())
.withMatcher("lastname", startsWith().ignoreCase());
Example<Person> example = Example.of(new Person("Jon", "Snow"), matcher);
repo.count(example);
MORE INFO
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#query-by-example
https://github.com/spring-projects/spring-data-examples/tree/master/jpa/query-by-example
Spring Data JPA: Query by Example?
Yes, please take a look at the QueryDSL support for Spring Data. Your use case can be implemented via a Predicate. In a nutshell, you have to create a predicate in which you would pass the non null fields, and then pass that predicate to a findAll method that takes a Predicate as argument. Your repository interface also has to extend QueryDslPredicateExecutor
Need to extend repository from JpaSpecificationExecutor
#Repository
#Transactional
public interface EmployeeDAO extends CrudRepository<Employee,Long>,JpaSpecificationExecutor<Employee>{
}
Use specification and predicate like below
public List<Employee> findByCriteria(String employeeName,String employeeRole){
return employeeDAO.findAll(new Specification<Employee>() {
#Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> predicates = new ArrayList<>();
if(employeeName!=null) {
predicates.add(criteriaBuilder.and(criteriaBuilder.like(root.get("employeeName"), "%"+employeeName+"%")));
}
if(employeeRole!=null){
predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("employeeRole"), employeeRole)));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
});
}
Thank U, guys! I have found the solution:
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query(value = "select * from Book where find_in_set(:market,market)", nativeQuery = true)
public List<Book> findBooksByMarcket(#Param("market") String market);
}
Original question
I'm using the #Query annotation to create queries by using the JPA query language and to bind these queries directly to the methods of my repository interface.
My database is created correctly and I'm successful to create some queries except this one:
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query("select b from Book b where find_in_set(:market,b.market)")
public List<Book> findBooksByMarcket(#Param("market") String market);
}
I can get the correct result by using the find_in_set function when I check it though MySql. But I cannot reach to pass a variable in java. I have searched though the internet but I cannot find the correct format for it.
please help and thank you guys!
A quick solution is to transform the JPQL query to a native query (by setting the nativeQuery flag to true):
#Query(value = "select * from Book b where find_in_set(:market,b.market)", nativeQuery = true)
public List<Book> findBooksByMarcket(#Param("market") String market);
If you have a custom MySQL function and want to utilize it in a JPA repository, please take a look at tip 1
There is another way to do it using CriteriaBuilder (I used this mechanism along with JPA specification): tip 2
Key words for your search: custom db function, JPA specification, CriteriaBuilder, Criteria
Try this
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query("select b from Book b where find_in_set(?1,b.market)")
public List<Book> findBooksByMarcket(String market);
}