Change default sort order for Spring Data findAll() method - spring

I'm using Spring Data JPA and I wonder if it is possible to change the default sort order for a entity being used by the Spring Data findAll() method?

You can achieve this as follows:
dao.findAll(new Sort(Sort.Direction.DESC, "colName"));
// or
dao.findAll(Sort.by("colName").descending());
Another way to achieve the same. Use the below method name:
findByOrderByIdAsc()

You should be able to do this by either:
in spring-data 1.5+, overriding the findAll() method in your Interface, adding the #Query annotation and creating a named Query in your Entity class like, for example, below:
Entity
#Entity
#NamedQuery(name = "User.findAll", query="select u from User u order by u.address.town")
public class User{
}
Repository
public interface UserRepository extends ... <User, Long> {
#Override
#Query
public Iterable<User> findAll();
}
or,
by creating a custom repository implementation:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

Use a PagingAndSortingRepository instead.
With that in place you can add a queryparameter ?sort=,
Repository:
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
//no custom code needed
}
GET Request:
localhost:8080/users?sort=name,desc

If you want to add costom query to findAll() jpa query you can do it this way
here i changed my default order
According to my default order is primary key it is id
but now i here set id_order to change my default order
Model class
#Entity
#Table(name = "category")
#NamedQuery(name = "Category.findAll", query="select u from Category u order by
u.id_order")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String nameEn;
private String nameSi;
private String nameTa;
private Integer id_order;
Repository class
import com.model.Category;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface CategoryRepository extends CrudRepository<Category, Integer> {
#Override
#Query
public Iterable<Category> findAll();

Related

Spring data-JPA repository.save() is not updating entity

My classes are like..
Employee Entity:
import javax.persistence.Entity;
import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.PrePersist;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
#Entity
#Data
#DynamicUpdate
#EntityListeners(AuditingEntityListener.class)
#Table(name = "tbl_employee", indexes = {
#Index(name = "idx_employee_status", columnList = "status"),
#Index(name = "idx_employee_createdAt", columnList = "createdAt") })
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
private String name;
private String remarks;
private String status;
#PrePersist
public void setCreatedAt() {
this.createdAt = OffsetDateTime.now();
}
}
Repository:
public interface EmployeeRepository extends CrudRepository<Employee, Long>, PagingAndSortingRepository<Employee, Long>{
}
Service methods:
createEmployee(){
Employee employee = new Employee();
employee.setName("John");
employee.setRemarks("Very Good Performance");
employeeRepository.save(employee);
}
updateEmployee(){
Employee employee = employeeRepository.findById(1L); // Id is long
employee.setName("Thomas");
employee.setRemarks("Above average Performance");
employeeRepository.save(employee);
}
createEmployee() is working and data is getting saved in DB (MySQL), but updateEmployee() is not. No sql query is generated in the eclipse console.
AM I missing something in configuration?
Make sure that the service methods are annotated with #Transactional.
Otherwise the hibernate cannot track changes which are needed for #DynamicUpdate.
Alternatively you can also try to remove the annotation.
Hibernate/JPA only access the database when it has to.
In the create variant it needs to return an instance with a updated ID value. The id value gets generated by the database when the insert is performed.
Therefore the insert is performed immediately.
In the other case no information from the database is required.
Therefore Hibernate/JPA only marks the entity as dirty and moves on.
Only when the transaction ends the update is actually performed.

Spring Data JPA Query by Example Returns Null

I have looked at numerous examples and tried various w/ & w/o example matcher constraints but whatever I do my query by example only returns null.
I am able to get the CRUD Repository data calls to work without any issues, however I extended that to the JPA Repository and added the QueryByExampleExecutor interface. The findOne() does not seem to be working.
Using Spring Boot 2.2.6.RELEASE, spring-boot-starter-data-jpa and mysql 5.7.
When using query by example does the entire object need to be completed for matching? In other words, do all setters need the correct information? Or just the object data item that is to be matched?
And Yes, the database does contain only one correct string on which I am attempting to match.
Customer
#Entity
#Table(name="customer")
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private long id;
#Column(name="social_security_number")
private String socialSecurityNumber;
//Other data fields are included
}
CustomerRepository
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
QueryByExampleExecutor
import java.util.Optional;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
public interface QueryByExampleExecutor<T> {
<S extends T> Optional<S> findOne(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example, Sort sort);
<S extends T> Page<S> findAll(Example<S> example, Pageable pageable);
<S extends T> long count(Example<S> example);
<S extends T> boolean exists(Example<S> example);
}
CustomerService
public interface CustomerService {
public Customer findBySSN(String ssn);
}
CustomerServiceImpl
#Service
public class CustomerServiceImpl implements CustomerService {
private CustomerRepository customerRepository;
#Autowired
public CustomerServiceImpl(CustomerRepository theCustomerRepository) {
customerRepository = theCustomerRepository;
}
#Override
public Customer findBySSN(String ssn) {
//Create a new object to use as a basis for querying against
Customer customer = new Customer();
//Set the parameters for the query
customer.setSocialSecurityNumber(ssn);
//Create an example query
Example<Customer> customerExample = Example.of(customer);
Optional<Customer> result = customerRepository.findOne(customerExample);
if (result.isPresent()) {
return result.get();
} else {
// Didn't find the customer
throw new ObjectNotFoundException("Customer", "Social Security Number ("+ssn+") not found...");
}
}
}
Calling Method
#Autowired
private CustomerService customerService;
Customer ssnCustomer = customerService.findBySSN("123456789");
if(ssnCustomer == null) {
System.out.println("SSN NOT FOUND WAS NULL");
} else {
System.out.println("SSN FOUND "+ssnCustomer.getId());
}
What am I missing? Thank you in advance.
Change id type from long to Long. long is setting value as 0 automatically and making it part of query.
private Long id;
Change getter and Setter accordingly

No converter found capable of converting from type to type

I am getting the following stacktrace:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [referencedata.ABDeadlineType] to type [referencedata.DeadlineType]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:324)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:206)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:187)
at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:256)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter$1.convert(ResultProcessor.java:201)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:212)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:149)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:121)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy143.findAllSummarizedBy(Unknown Source)
at
My classes are the following
DeadlineType
#Data
public class DeadlineType extends DefaultIdAndText {
#Value("#{target.id}")
String id;
#Value("#{target.code}")
String text;
#Value("#{target.id}")
public String getId() {
return id;
}
#Value("#{target.code}")
public String getText() {
return text;
}
}
ABDeadlineType
#Data
#Entity
#Table(name = "deadline_type")
#AllArgsConstructor
#NoArgsConstructor
public class ABDeadlineType {
private #Id
String id;
private String code;
}
DefaultIdAndText
#Data #AllArgsConstructor
#NoArgsConstructor
public class DefaultIdAndText implements IdAndText {
public DefaultIdAndText(IdAndText idAndText){
this.id = idAndText.getId();
this.text = idAndText.getText();
}
#NotEmpty String id;
String text;
}
DeadlineTypeRepository
public interface DeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
List<DeadlineType> findAllSummarizedBy();
}
Update
Could it be an issue that the projection/mapping using #Value("#{target.id}") format, does not work correctly because these have been done on a class and not on an interface???
Return ABDeadlineType from repository:
public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
List<ABDeadlineType> findAllSummarizedBy();
}
and then convert to DeadlineType. Manually or use mapstruct.
Or call constructor from #Query annotation:
public interface DeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
#Query("select new package.DeadlineType(a.id, a.code) from ABDeadlineType a ")
List<DeadlineType> findAllSummarizedBy();
}
Or use #Projection:
#Projection(name = "deadline", types = { ABDeadlineType.class })
public interface DeadlineType {
#Value("#{target.id}")
String getId();
#Value("#{target.code}")
String getText();
}
Update:
Spring can work without #Projection annotation:
public interface DeadlineType {
String getId();
String getText();
}
You may already have this working, but the I created a test project with the classes below allowing you to retrieve the data into an entity, projection or dto.
Projection - this will return the code column twice, once named code and also named text (for example only). As you say above, you don't need the #Projection annotation
import org.springframework.beans.factory.annotation.Value;
public interface DeadlineTypeProjection {
String getId();
// can get code and or change name of getter below
String getCode();
// Points to the code attribute of entity class
#Value(value = "#{target.code}")
String getText();
}
DTO class - not sure why this was inheriting from your base class and then redefining the attributes. JsonProperty just an example of how you'd change the name of the field passed back to a REST end point
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
#Data
#AllArgsConstructor
public class DeadlineType {
String id;
// Use this annotation if you need to change the name of the property that is passed back from controller
// Needs to be called code to be used in Repository
#JsonProperty(value = "text")
String code;
}
Entity class
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Data
#Entity
#Table(name = "deadline_type")
public class ABDeadlineType {
#Id
private String id;
private String code;
}
Repository - your repository extends JpaRepository<ABDeadlineType, Long> but the Id is a String, so updated below to JpaRepository<ABDeadlineType, String>
import com.example.demo.entity.ABDeadlineType;
import com.example.demo.projection.DeadlineTypeProjection;
import com.example.demo.transfer.DeadlineType;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, String> {
List<ABDeadlineType> findAll();
List<DeadlineType> findAllDtoBy();
List<DeadlineTypeProjection> findAllProjectionBy();
}
Example Controller - accesses the repository directly to simplify code
#RequestMapping(value = "deadlinetype")
#RestController
public class DeadlineTypeController {
private final ABDeadlineTypeRepository abDeadlineTypeRepository;
#Autowired
public DeadlineTypeController(ABDeadlineTypeRepository abDeadlineTypeRepository) {
this.abDeadlineTypeRepository = abDeadlineTypeRepository;
}
#GetMapping(value = "/list")
public ResponseEntity<List<ABDeadlineType>> list() {
List<ABDeadlineType> types = abDeadlineTypeRepository.findAll();
return ResponseEntity.ok(types);
}
#GetMapping(value = "/listdto")
public ResponseEntity<List<DeadlineType>> listDto() {
List<DeadlineType> types = abDeadlineTypeRepository.findAllDtoBy();
return ResponseEntity.ok(types);
}
#GetMapping(value = "/listprojection")
public ResponseEntity<List<DeadlineTypeProjection>> listProjection() {
List<DeadlineTypeProjection> types = abDeadlineTypeRepository.findAllProjectionBy();
return ResponseEntity.ok(types);
}
}
Hope that helps
Les
I have met the same problem recently with spring-data-jpa:2.5.0.
Solution (for queries with no #Query annotation):
For class-based projection (DTOs), the problem is the #NoArgsConstructor in the DTO class. Revemoving it should make things work.
Something interesting I found during debug:
With the presence of a non argument constructor, the returnedType somehow was created with 0 input properties.
When a query is actually created, JpaQueryCreator (spring-data-jpa) would check if it needs to do custom construction according to the number of input properties.
As it's not the case with 0 input properties, it would then return the whole entity instance.
https://github.com/spring-projects/spring-data-jpa/blob/main/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java#L169
Finally when the result is being returned, the target type and returned type don't match, as there is no converter available to convert from the entity instance to the projectiong dto. The error was thrown.
https://github.com/spring-projects/spring-data-commons/blob/main/src/main/java/org/springframework/data/repository/query/ResultProcessor.java#L162
Simple Solution::
use {nativeQuery=true} in your query.
for example
#Query(value = "select d.id,d.name,d.breed,d.origin from Dog d",nativeQuery = true)
List<Dog> findALL();
If you look at the exception stack trace it says that, it failed to convert from ABDeadlineType to DeadlineType. Because your repository is going to return you the objects of ABDeadlineType. How the spring-data-jpa will convert into the other one(DeadlineType). You should return the same type from repository and then have some intermediate util class to convert it into your model class.
public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
List<ABDeadlineType> findAllSummarizedBy();
}
Turns out, when the table name is different than the model name, you have to change the annotations to:
#Entity
#Table(name = "table_name")
class WhateverNameYouWant {
...
Instead of simply using the #Entity annotation.
What was weird for me, is that the class it was trying to convert to didn't exist. This worked for me.
Well I have another answer I have used Interfaces for Projections and Classes for
Dto's and I am using ModelMapper to map my Projections to Dto Class
So my 1 Dto class may have many Projections which can mapped to Dto and used to Taste
gradle
implementation 'org.modelmapper:modelmapper:3.1.0'
#Autowired
private ModelMapper modelMapper;
List<UserDto> usersdto = repository.findUserByRoleName().stream().map(userprojection -> modelMapper.map(userprojection, UserDto.class))
.collect(Collectors.toList());
My projection is like this
public interface UserProjection {
String getId();
String getEmail();
}
My dto is
#Data
#AllArgsConstructor
#NoArgsConstructor
public class UserDto {
private long id;
private String firstName;
private String lastName;
private String phone;
private String email;
}
And I am able to get fields from custom queries
Change the class name to DeadlineType inside
extends JpaRepository<class, type>
For example:
In your code, the repository where you placed you query extends JpaRepository that with class and id type <ABDeadlineType, Long>. So it expects to return ABDeadlineType data.
public interface DeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
List<DeadlineType> findAllSummarizedBy();
}
As you want to get DeadlineType data, you should keep your query in such repository like
public interface DeadlineTypeRepository extends JpaRepository<DeadlineType, Long>
So, either replace the class name inside JpaRepository<>
Or place your query in another repository. Then you don't need to do any mapping or write extra codes for it.
In my case, it worked.

How to get data from a table by entity class name using Spring Data JPA

I have a base entity class BaseDictionary:
#Entity
#Inheritance
public abstract class BaseDictionary {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
#Column(name = "code")
protected String code;
#Column(name = "is_enabled")
protected Boolean enabled = true;
}
any child classes
#Entity
#Table(name = DB.DIC_RIGHTS_TYPE, schema = DB.SCHEMA_DIC)
public class DicRightsType extends BaseDictionary {}
#Entity
#Table(name = DB.DIC_ROLES_TYPE, schema = DB.SCHEMA_DIC)
public class DicRolesType extends BaseDictionary {}
There are many child classes like this.
Given an entity class name like DicRightsType I would like to get data from the table associated with the entity of that name. How is it possible to implement?
I wanted to use JPA repositories like this: Using generics in Spring Data JPA repositories but this does not suit my case because I only have the name of the entity class at runtime and do not know how to create a dynamic repository for the class.
You can write your own JpaRepository implementation to achieve this.
Step 1: A repository registry
class RepositoryRegistrar {
private static final Map<Class<T>, Repository<T, Serializable>> DICTIONARY = new HashMap<>();
public static void register(Class<T> entityClass, Repository<T, Serializable> repository) {
DICTIONARY.put(entityClass, repository);
}
public static Repository<T, Serializable> get(Class<T> entityClass) {
return DICTIONARY.get(entityClass);
}
}
Step 2: Custom JpaRepository implementation to populate the registry
#NoRepositoryBean
class RegisteringJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> {
public RegisteringJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {{
super(entityInformation, entityManager);
RepositoryRegistrar.register(entityInformation.getJavaType(), this);
}
}
You will have to tweak the configuration to use your custom implementation. Details for this are provided in the Spring Data JPA documentation.
Step 3: Obtain repository references from the registrar
Repository<?, ?> getRepository(String entityClassName) {
return RepositoryRegistrar.get(Class.forName(entityClassName));
}

How to write custom query in Mongo Spring Data JPA

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
#Repository
public interface PersonRepository extends MongoRepository<Person, String> {
#Query("{ 'firstname' : ?0 }")
List<Person> findByFirstname(String firstname);
}
I am using spring data jpa with MongoDB. I am able to save, delete or retrieve (all records) using repository.
I am trying to retrieve record based on a property value. (Custom Query shown above). This does not work.
Can someone help me in finding out how to write custom Queries in MongoRepository where I can pass a column value and get the matching rows.
EDIT:
Adding Code.
#Document/*(collection = "person")*/
public class Person {
#Id
private String id;
private String firstName;
private String lastName;
private Address address;
// gettters and setters
}
#Service
public class PersonServiceImpl{
#Autowired
private PersonRepository personRepository;
public Person findPersonByFirstName(String firstName) {
List<Person> person = personRepository.findAllByFirstName(firstName);
System.out.println("** Data Retrieved **" );
return person.get(0);
}
}
You don't need a custom query for this kind of query.
Following should just work (provided your field in Person class is "firstname" - is that righ?)
List<Person> findAllByFirstname(String firstname);
Does your query work from a mongo console?

Resources