Do we need #Transactional only for write methods in spring data jpa? - jpa

For example, I have two repository methods such as
#Query("select * from person where name = ?1", nativeQuery = true)
Person findPersonByName(String name);
#Modifying
#Query("delete from person where id = ?1", nativeQuery = true)
int deletePersonById(Long id);
Here the first method works fine and returns an entity person.
But second method throws TransactionRequiredException.
As per the docs, CrudRepository methods are by default transactional.
I understand from this statement that those methods of Repository and CrudRepository are marked #Transactional in proxy classes implementing repositories, and custom query methods are NOT transactional.
If this is the case, don't we need transactional annotation on my first method? How does it work without transactional?
Why second method works only if I include transactional annotation?
I tried adding transactional annotation on second method and it works.
But why first method doesn't need this annotation and why first one works even without explicitly applied transactional annotation?

This boils down to the specification of the EntityManager. It basically requires a transaction for writing operations (merge, persist, delete) and does not need one for reading operations.

Related

Does Spring Data intentionally allow for unknown tokens when generating queries from method names?

In one of my Spring Data repositories I wanted to have two autogenerated methods for finding a single instance by ID, one returning the full entity (Student) and the other a slimmer projection (StudentView). Now obviously Java won't let me have two methods that differ only in return type:
Optional<Student> findById(String id);
Optional<StudentView> findById(String id);
I could have named one of the methods to whatever else I wanted and manually provided it with the required query via a #Query annotation, but I wanted to make use of method-name autogeneration. Now Spring Data does allow for some flexibility in how it parses the method name, and so I could have named one of the methods as (say) findOneById() to distinguish it from the other, but that didn't feel right. However in the course of experimentation I discovered that I could name the second method as findViewById(), that is containing a token View that is not one of the keywords known to the method-name parser:
Optional<Student> findById(String id);
Optional<StudentView> findViewById(String id);
Does the method-name parser intentionally allow for this (I cannot find mention of it in the documentation), or am I merely exploiting an accident of implementation?
This looks bizarre, but it looks like in Spring-Boot 2.2.2.RELEASE you can use whatever word you want between find and ById.
Optional<Student> findWhateverById(Long Id) will return record of student table with provided id.
Either I'm missing something or it's indeed a bug.

Spring JPA findBy accent

I am developing a spring-data-jpa application.
I 've ridden the repository with findBy but does not work when I look content with an accent. Does anyone know why?
I am using the following:
Page<Dades> findByNomcomercialIgnoreCaseContaining (#Param ("nomcom") String nomcom, Pageable pageable);
The database is Oracle.
Thanks for your interest.
It's because ignoreCase does not deal with accents. It only compares both String after uppercasing them. See the documentation for more informations.
I don't know any simple solution to ignore accents with Spring Jpa. You coud either :
Remove this parameter in your query, and filter the result in Java afterward (comparing Strings after doing org.apache.commons.lang3.StringUtils.stripAccents).
Use Spring Jpa Specifications. Again, it provides only functionslike upper, like, ... so you have to write your own, depending on what database you are using.
#Param is not required. if you have any query i.e if you are using #Query then we need use #param to pass the specific value releated to query.Below you can check how to use #Query and #Param
#Query("SELECT t.title FROM Todo t where t.id = :id")
String findTitleById(#Param("id") Long id);
if you are not added these annotation use in your repository layer
#Transactional
#Repository
Check another thing i.e
#Transactional
#Repository
public interface IXyzRepository extends CrudRepository<ABC,Integer>{
//some methods you have
}
whether the primary id of class ABC is of type Integer

Is #NamedQuery necessary when mapping entity to a view?

From many examples online, I saw people add #NamedQuery before their entity class, I removed the annotation and it still works, so I am curious if it's necessary to always add this annotation to entities? BTW, I am using Spring data as the JPA vendor.
What's the best practice here and why?
#Entity
#NamedQuery(name = "User.findByEmailAddress",
query = "select u from User u where u.emailAddress = ?1")
public class User {
//Do stuff
}
No, named queries are not needed. They allow you to predefine queries and then use them at runtime rather than dynamically creating each query. This is described in the docs here

Spring LDAP JPA - Limit number of result

I'm using spring-ldap 2.0.4 and spring-data-jpa 1.9.0.
I built a JPA repository like this :
public interface PersonRepo extends LdapRepository<Person> {
Person findByUid (String uid);
#Query("(&(attribute=*{0}*)(attribute2=X)(attribute3=Y))")
List<Person> findByAttributeContains(String attribute);
}
So far everything is fine. I could write methods that fill my needs thanks to query methods.
For some queries i had to use #Query annotation because they were many and operator.
But i would like to limit the number of result to return from my second query method.
I know there is there is the Top and First keywords to define query methods in spring JPA. But I didn't manage to get it work. Plus I want to use multiple and operator in the method.
Thanks
I managed to limit the number of result using XML LDAP configuration.
<ldap:ldap-template context-source-ref="contextSource" count-limit="100"/>

Using Annotations In JPA can I limit child records with a where clause?

I have an EJB with an #onetomany relationship like this in my parent class (Timeslot):
#OneToMany(mappedBy = "rsTimeslots")
private List<RsEvents> rsEventsList;
I also have a function to get the rsEventList:
public void setRsEventsList(List<RsEvents> rsEventsList) {
this.rsEventsList = rsEventsList;
}
This was all auto generated so far. In my view-layer code I can get a timeslot object and do something like timeslot.getRsEventList() and get all children of this timeslot. Now I need to restrict that list based on a criteria. For example I only want events that are children of this timeslot with a status of 1. Is there a way to do this with annotations?
Not in JPA.
Normally you would execute a Query for this, using JPQL or the criteria API.
Some JPA providers do provide ways to restrict relationships, but I think you would be best off with a query, or providing a get/filter method on your class that just accesses the list and filters it (i.e. getStatus1Events()).
For an EclipseLink example of having a criteria on a mapping see,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/MappingSelectionCriteria