When using CrudRepository how can I use transformers - spring

I have read this article
https://smarterco.de/spring-data-jpa-query-result-to-dto/
And tried this.
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
#Query("SELECT u FROM User AS u")
List<User> findAll();
#Query("SELECT new de.smarterco.example.dto.UserNameDTO(u.id, u.name) FROM User u WHERE u.name = :name")
List<UserNameDTO> retrieveUsernameAsDTO(#Param("name") String name);
}
And it works.
But lets say my User had a list of Address. And my UserNameDTO also had a corresponding dto. How could I do that?
Can I somehow attach a resultTransformer to the query? or register a converter?
Looking forward to your suggestions.
Best regards. Ole Bille

Related

Is there a JpaRepository method which can save a provided password where username condition?

I am looking for a JpaRepository method to update a user provided password at the time of resetting it with a username condition . Thanks in advance
Have a look at creating custom query methods with JPA as per documentation: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query.
For your use case, the following would allow you update the correct user's password:
#Repository
public interface UserRepository extends JpaRepository<User, UUID> {
#Query("update User u set u.password= ?1 where u.username = ?2")
void updatePassword(String username, String password);
}
In Spring Data JPA, whenever you execute an update, you need to use the #Modifying along with the #Query. Failing to use the #Modifying will result in InvalidDataAccessApiUsage exception.
Find the code below
#Repository
public interface UserRepository extends JpaRepository<User, UUID> {
#Modifying
#Query("update User u set u.password= :password where u.username = :username")
void updatePassword(#Param("username") String username, #Param("password") String password);
}

How do I use custom SQL in sprint data repository?

I`m using Repository like this:
public interface UserRepository extends Repository<User, Long> {
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
But what I need is execute my own sql statement.
select u.* from users u where exists ( select 1 from expires_users where users_id = u.id )
Please, past link references in answers.
I think you can do as pointed in the documentation of Spring Data JPA.
Here is an example:
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u.* from User u
where exists(select 1 from ExpiredUser e where e.id = u.id)")
Page<User> findExpiredUsers(Pageable pageable);
}
The Page and Pageable parts are for paging results, assuming that this query could return many more results than you would like to process at once. More information on paging results can be found here.

Spring CrudRepository findBy exclusionary?

I have a CrudRepository 'custom' find method that's working as follows:
public interface ProductRepository extends CrudRepository<Product, Integer>{
List<Product> findAllByVendorID(int id);
}
And to call it I do the following:
List<Product> products = productRepository.findAllByVendorID(vendor.getId());
But if I want the opposite result, or all the products that aren't associated with that vendor id, is there an easy way to do that?
This should suffice.
List<Product> findAllByVendorIDNot(int id);
You can extend this for multiple Id's as well
List<Product> findAllByVendorIDNotIn(List<Integer> ids);

JPA #Query annotation does not seem to be using paramter

I have a Spring Boot application using JPA/Hibernate as entity management/modeling. I have the following user class:
#Entity
public class User {
#Id
private Long Id;
private String name;
//more fields, getters and setters below
}
I want users of my application to be able to search for users by name. So in my repository interface, I have:
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT u from User u WHERE lower(u.name) LIKE lower(:name)")
List<User> findByNameLike(#Param(value="name") String nmae);
}
Then in my UserController, I have:
#GetMapping(value = "/users/")
public #ResponseBody List<User> search(#RequestParam String name) {
return this.userRepository.findByNameLike(name);
}
This always returns an empty list. I know the name parameter is coming in correctly.
Moreover, I do know that it is recognizing the #Query annotation, because if I change the query to something like
SELECT u FROM User u
it will return me all users. Or if I change it to
SELECT u from User u WHERE u.name = '%Bob%'
and remove the parameter from the method, it will return all users whose name is Bob. I've tried other variations of the query, such as
SELECT u FROM User u WHERE lower(u.name) LIKE CONCAT('%', lower(:name), '%')
SELECT u FROM User u WHERE u.name = :name (even a simple equals doesn't work)
and so on and so forth. Every source I look at whose syntax I copy seems to say I'm writing the query right, so I think something else must be going on.
I've also tried letting Spring generate the query for me, using
public List<User> findByNameLike(String name);
public List<User> findByNameContaining(String name);
which also don't seem to work. Any help would be appreciated here!

#NamedQuery override findAll in Spring Data Rest JpaRepository

Is there a way to override the findAll query executed by Spring Data Rest?
I need a way of filtering the results based on some specific criteria and it seems that using a #NamedQuery should be along the lines of what I'm looking for so I setup a test.
#Entity
#Table(name = "users")
#NamedQueries({
#NamedQuery(name = "User.findAll", query="SELECT u FROM User u WHERE u.username = 'test'"),
#NamedQuery(name = "User.findNameEqualsTest", query="SELECT u FROM User u WHERE u.username = 'test'")
})
public class User implements Serializable, Identifiable<Long> { }
With this in place I would expect SDR to utilize my findAll() query (returning 1 result) but instead it executes the same old findAll logic (returning all results).
In my Repository I added:
#Repository
#RestResource(path = "users", rel = "users")
public interface UserJpaRepository extends JpaRepository<User, Long> {
public Page<User> findNameEqualsTest(Pageable pageable);
}
and in this case it DOES pick up the provided #NamedQuery. So...
How should I go about overriding the default findAll() logic? I need to actually construct a complex set of criteria and apply it to the result set.
In the upcoming version 1.5 (an RC is available in our milestone repositories) of Spring Data JPA you can simply redeclare the method in your repository interface and annotate it with #Query so that the execution as query method is triggered. This will then cause the named query to be looked up just as you're already used to from query methods:
interface UserJpaRepository extends PagingAndSortingRepository<User, Long> {
#Query
List<User> findAll();
Page<User> findNameEqualsTest(Pageable pageable);
}
A few notes on your repository declaration:
You don't need to annotate the interface with #Repository. That annotation doesn't have any effect at all here.
Your #RestResource annotation configures the exporter in a way that will be the default anyway in Spring Data REST 2.0 (also in RC already). Ging forward, prefer #RestRepositoryResource, but as I said: the pluralization will be the default anyway.
We generally don't recommend to extend the store specific interfaces but rather use CrudRepository or PagingAndSortingRepository.
Yes, you can create your Implementation of your Repository interface, there is acouple section in
http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/repositories.html#repositories.custom-implementations
Repository
#Repository
public interface PagLogRepository extends JpaRepository<PagLogEntity, Long>, PagLogCustomRepository {
Custom Interface
public interface PagLogCustomRepository {
PagLogEntity save(SalesForceForm salesForceForm) throws ResourceNotFoundException;
Custom implementation
public class PagLogRepositoryImpl implements PagLogCustomRepository {
#Override
public PagLogEntity save(final SalesForceForm salesForceForm) throws ResourceNotFoundException {
query = emEntityManager.createNamedQuery("findItemFileByDenormalizedSku", ItemFileEntity.class);
query.setParameter("skuValue", rawSku);
Instead of override save make it with findAll, then you can create complex customization

Resources