Custom delete method in JpaRepository - spring

I'd like to know if there's a way of overriding the delete method for some of my JpaRepository's without having to override the rest of the methods.
Currently I have something like
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
And I'd like to override the delete(T Entity) method in CrudRepository. To do so I've tried implementing the UserRepo but then I have to implement all the findByX and haven't really find anything around on how to properly do that.
Is there any annotation to add to a function in the Entity class so it runs when you call UserRepo.delete(myUser)?
Thanks in advance!

Not sure I understand you clear enough, but lets try:
... I have to implement all the findByX ...
You don't, spring will generate JPQL snippet if you name methods in your interface with suitable convection please take a look at this and this articles
... Is there any annotation to add to a function in the Entity class
so it runs when you call UserRepo.delete(myUser)? ...
You can use #PreRemove / #PostRemove annotation on method in your entity class:
#PreRemove / #PostRemove
public void someMethod() { ... }

In addition to Raheela Aslam post:
Spring-data documentation has an example of how you can override standard repository methods, for example:
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}
You can read about it there:
https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#repositories.custom-implementations
UPD:
Read it carefully, because there are some important things, e.g
The most important part of the class name that corresponds to the fragment interface is the Impl postfix.
Also the documentation says:
Custom implementations have a higher priority than the base implementation and repository aspects.

If you want to keep Spring's behavior for deletion, but want to have some logic to be executed either before or after, you may utilize java8's interface default methods, and try the following :
public interface UserRepo extends JpaRepository<User, Long> {
default void customDelete(User user) {
// before logic
// ..
delete(user); // actual call to deletion
// after logic
// ..
}
}

There are several ways to do this depending on what you're trying to do:
Use method naming, and let Spring derive the JPQL query from the naming (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-from-method-names/)
Use the Query annotation and add the desired JPQL query in the annotation (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-the-query-annotation/)
Use a named query (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-named-queries/)
I prefer to use method naming if possible, the method name gets long, but you know exactly what it does by looking at it.

In your case code will be like as below:
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
public interface UserRepositoryCustom {
void deleteByEmail(String email);
}
public interface UserRepositoryImpl implements UserRepositoryCustom {
public void deleteByEmail(String email) {
//provide your custom implimentation
}
}

Hi you can write your own Interface write implementation with EntityManager and
extend in you interface here is the sample :
https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa
Actually one more way is writing by soemthing like :
User findByUsername(String username) // it will find the user by specific username
spring data will create you an implementation of this method
The same way you can create your own delete method
Here is useful links:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
In this link you can go to part 2.3 QueryMethods:
https://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/html/jpa.repositories.html
You can also define #NameQuery in your entity class:
#Entity
#Table(name = "employee", schema="spring_data_jpa_example")
#NamedQuery(name = "Employee.yourMethodQueryName",
query = "yourQuery"
)
public class Employee {}
#Repository
public interface EmployeeRepository extends JpaRepository<Employee,Long> {
List<Employee> yourMethodQueryName(Your list of params);
}
Here is link with sample:
https://www.logicbig.com/tutorials/spring-framework/spring-data/jpa-named-queries.html
I think this is helpful for you

public interface UserRepo extends JpaRepository<User, Long> {
#Modifying
#Query("delete from User u where u.email = ?1")
void deleteByEmail(String email);
}

Related

need help on understand why my customized repository work

I have customized repository to include query methods and customized method. I get it working as blow.
public interface UserRepository extends ElasticsearchRepository<User, String>{
query_method_A();
query_method_B();
My_customized_method();
}
public class UserRepositoryImpl{
My_customized_method(){
//my real implementation
}
}
I don't need to add any annotation. Spring creates two beans.
userRepository : class com.sun.proxy.$Proxy150
userRepositoryImpl : class com.*.repository.impl.userRepositoryImpl
UserRepositoryImpl can't have implements UserRepository , otherwise it complains that it needs to implement those query methods. It works fine.
I was reading a document about Customizing Individual Repositories https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behavior
It seems that the correct way is to use a fragment repository like below. No annotation is needed. Tested and worked.
public interface UserRepository extends ElasticsearchRepository<User, String>, MyTestRepository
{
query_method_A();
query_method_B();
}
public interface MyTestRepository {
My_customized_method();
}
public class MyTestRepositoryImpl implements MyTestRepository {
My_customized_method(){
//my real implementation
}
}
My question is why does my first custom repository work? It seems more convenient to use though since I only need one Impl class per repository.

How to configure spring JpaRepository to be one of the implementations of an interface

Hello I'm working on a task where based on configuration I need to use either a custom implementation of a repository that uses an api to fetch data or a normal repository that extends a JpaRepository.
So something like this:
public interface PersonRepository {
Person findPersonById(Long id);
}
and the possible implementations for that would be:
public interface PersonDatabaseRepository extends PagingAndSortingRepository<Person, Long>, JpaSpecificationExecutor<Person>{
Person findPersonById(Long id);
}
public class PersonApiRepository extends implements PersonRepository {
public Person findPersonById(Long id) {
return someApiClient.findPersonById(id);
}
}
Is that possible? I know I could add another interface in the upper layer where the implementations would use either PersonDatabaseRepository or PersonApiRepository inside but I was wondering if it would be possible to skip that

Spring Data Rest Save Iterable Entity

I've tried many different ways to pass an array of JSON to a Spring Data Rest Repository, not sure how to do it. I have a custom respository interface that is extending Repository:
#NoRepositoryBean
interface BaseRepository<T, ID extends Serializable> extends Repository<T, Long> {
T save(T entity)
List<T> save(Iterable<T> entities)
}
I can save a single entity, but when I try to pass an array of JSON objects I get an error cannot deserialize instance...
Not sure how to pass the object so that I can do a batch insert.
Unfortunatly you don't post the code that uses your interface, bug if you are actually passing an array as you describe in the question, you are not calling List<T> save(Iterable<T> entities) but T save(T entity). Arrays are not Iterables so the compiler will interpret your array as T and since an array is not an entity you get the error.
Convert the array to an Iterable to fix this. Arrays.asList(someArray) does the trick.
I seemed to work around it by overriding the save method, I'm sure there is a better way, I am open to suggestions.
BaseRepository
#NoRepositoryBean
interface BaseRepository<T, ID extends Serializable> extends Repository<T, Long> {
#RestResource(path="byIdIn",rel="byIdIn")
#Query("select r from #{#entityName} r where r.id in :q")
Page<T> findByIdIn(#Param("q") List<Long> q, Pageable pageable)
Page<T> findAll(Pageable pageable)
T findOne(ID id)
T save(T entity)
T delete(ID id)
}
ContactRepository
#RepositoryRestResource(collectionResourceRel="contacts", path="contacts")
interface ContactRepository extends BaseRepository<Contact, Long>, ContactRepositoryCustom {
}
ContactRepositoryCustom
interface ContactRepositoryCustom {
public <S extends Contact> S save(S entity)
}
ContactRepositoryImpl
#NoRepositoryBean
class ContactRepositoryImpl implements ContactRepositoryCustom {
#PersistenceContext
private EntityManager em
#Transactional
#Override
public <S extends Contact> S save(S entity) {
Contact contact = entity as Contact
try {
em.persist(contact)
contact.getComment().each {
Comment comment = new Comment(contact, it)
em.persist(comment)
}
} catch (Exception e) {
println e
}
return contact
}
}
This is just a sample, it needs some cleaning up, but I have the save() method working as expected. I just don't want to over do it if there is a baked in way in Spring Data / Spring Data Rest to do this kind of thing with annotations without having to roll a solution like this. I searched through the docs and online, but did not find a solution. I may have overlooked something, not sure.

Spring Data JPA custom method causing PropertyReferenceException

I have been trying to create a spring boot application. In my application I would like to add some custom methods to save the data instead of using the default save method.
My application entry point is something like this:
#Configuration
#ComponentScan
#EnableJpaRepositories(repositoryImplementationPostfix = "CustomImpl")
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
#PropertySource("application.properties")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have changed this line repositoryImplementationPostfix to even Impl but, it didn't work.
My CrudRepository
#RepositoryRestResource
public interface TaRepository extends CrudRepository<Ta, Integer> ,TestRepository{
List<Ta> findByName(#Param("name") String name);
}
My Custom Repository:
public interface TestRepository {
public void myCustomMethod(TestDto dto);
}
My Custom Repository Impl
public class TestRepositoryCustomImpl implements TestRepository{
#PersistenceContext
private EntityManager em;
#Override
public void myCustomMethod(TestDto model){
}
NOTE:
If I change my CrudRepostory from the mentioned to this:
#RepositoryRestResource
public interface TaRepository extends CrudRepository<Ta, Integer> {
List<Ta> findByName(#Param("name") String name);
}
everything works fine. But not with the custom method implementation.
For Spring Data JPA #Repository or #RepositoryRestResource you never need to implement a Custom Interface. For any simple query you can create any kind of method, please follow the simple guide.
http://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html
For a complex query you can use JpaSpecificationExecutor.
How can I create a Predicate from a HQL query?

Xtend picks the wrong overload

I'm playing with Xtend, and have hit a roadblock.
My class uses a Spring Data repository. Here's the interface:
public interface UserRepository extends GraphRepository<UserNode>, RelationshipOperationsRepository<UserNode> {
public UserNode findByEntityId(Long entityId);
}
the super interface of GraphRepository<T> (which is part of Spring Data, not my project) declares the following:
#Transactional
<U extends T> U save(U entity);
#Transactional
<U extends T> Iterable<U> save(Iterable<U> entities);
However, the following code fails for me:
// UpdateUserProcessorExample.xtend
class UpdateUserProcessorExample {
#Autowired
UserRepository repository
def updateUser()
{
var user = repository.findByEntityId(1L)
// The following line generates an error:
repository.save(user)
}
}
This generates:
Bounds mismatch: The type argument is not a valid substitute for
the bounded type parameter of the method
save(Iterable)
It appears as though Xtend is picking the wrong overloaded method.
I've tried adding type hints, ala:
var UserNode user = repository.findByEntityId(1L)
But this still generates the same error.
What am I doing wrong here?
On the Xtend mailing list, Sven advised he's raised a bug for this issue:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=413138
He also offered the following work-around:
A not so nice solution is to override the respective methods in
UserRepository and replace T by UserNode, like this :
public interface UserRepo extends GraphRepository<UserNode> {
UserNode findByEntityId(Long entityId);
#Override UserNode save(UserNode entity);
#Override <U extends UserNode> Iterable<? extends U> save(Iterable<? extends U> entities);
I don't understand why you have introduced additional type parameters on the methods, can't you you just use the one from the class level?
#Transactional
T save(T entity);
#Transactional
Iterable<? extends T> save(Iterable<? extends T> entities);
That should work.

Resources