When a method is created under a specific rule of Spring Data JPA, a method that calls the corresponding query is created.
For example,
public interface CustomerJpaRepository implements JpaRepository<Customer, Long>{
public List<Customer> findByName(String name);
}
findByName() generate the query similar to one below.
select * from Customer where name = name;
I am curious about this principle. To be precise, I'm curious about the code that parses this method and turns it into a query.
I looked at the code of the SimpleJpaRepository class that implements JpaRepository, but could not find a clue. (Of course, there is a possibility that I did not find it).
In summary, when a method consisting of specific words is declared in JpaRepository, I am curious about the code that actually executes this method internally. More specifically, I'd like to see the code that makes this method works.
If there is no code to do this internally (I personally doubt it's possible...), I want to know how it is implemented in detail, if there is a link or material that explains the principle or internal process, please share related references.
The parsing logic for creating queries from spring-data repository method names is currently mainly declared in the package org.springframework.data.repository.query.parser.
Basically, a repository method name string is parsed into a PartTree, which contains Parts representing defined abstract query criteria.
The PartTree can then be used to create a more specific query object, e.g. with a JpaQueryCreator, or a RedisQueryCreator, depending on the type of repository.
I recommend you to check this Query Creation spring doc
It explains the rules of how the method convert into a query.
Related
I am wondering how does Spring JPA derive queries from methods. As an example, if I was to type
interface CarRepo extends CrudRepository<Car, Long>{ findByCarMake(Make make) }
my query would be automatically derived from the method and would be something as "SELECT * from Car WHERE carMake = xxxxx"
I do understand this concepts but I would like to understand how it works behind the scenes. So, how does it actually derive a query from the method name?
I am aiming at creating a similar thing to suit our needs for a NestJs project so in Typescript not Java and also for an..."unorthodox" database which does not have such support out of the box( Neo4J).
I ll be very grateful to whom can and will help me.
Spring Data JPA derives the queries from the method names in your repository.
There are certain keywords that are reserved by Spring. One the one hand, there are query subject keywords like findBy, existsBy, countBy, etc. which influence the return type of the method. On the other hand, there are operators like and, or, isIn, between, etc. that are applied to the actual query logic.
You start your query with a query subject keyword like findBy and then the fields of your entity (and optionally operators and more fields). You can even have nested fields like findByProviderName where your entity has a field provider which has a field name. If you define an invalid property or property path (e.g. findByProviderNamw), your Spring Boot application would fail on startup. You can find more about defining query methods in the official spring reference.
Spring Data using part tree JPA queries, than map them into SQL query by pre-defined parts.
I was writing Java code to get all the rows from the database table.
I was using CrudRepository and used this method below.
public interface StudentRepository extends CrudRepository<Student, Long>
{
public List<Student> findById(long id);
}
or
#Query(value = "SELECT s FROM Student s")
List<Student> customMethod(long id);
Which method is faster? Does Java internal method provide faster than our custom query?
Thanks in advance.
The default findById provided by Spring Data Repository and a query-annotated method have significantly different semantics. But, to keep it short, I will try to focus on differences in performance exclusively.
Unless you have query cache enabled, a query-annotated method will always hit the database with a query.
findById, on the other hand, ultimately calls EntityManager.find(). EntityManager.find() looks up the entity in the persistence context first. That means if the entity has already been loaded into the context, the call will not hit the underlying database.
As a side note, if you're curious as to how Spring implements the default repository methods, have a look at the source of SimpleJpaRepository.
You have to understand that findAll() method eventually generates the query for the selection. The only way to prove that is to test it. I don't think you will gain a significant performance boost. JPA's, on another hand, query generation is extremely easy to understand and use. So, if you hesitate between using one or the other, I would stick to findAll() JPA or spring data repository methods.
Using Spring 5.0.6 and Spring-Data-Mongo 2.0.7, I have an issue when fetching entities being transformed into the wrong class. See the following simplified scenario:
Entity setup:
public class PersistableObject {
#Id #Field("_id") private String id;
}
#Document(collection = "myapp_user")
public class User extends PersistableObject {...}
public class RealUser extends User {...}
public class VirtualUser extends User {...}
So, there is a common MongoDB collection storing both types of User, discriminated by the automatically added _class property.
Furthermore, there is a Repository into which the MongoTemplate is injected.
#Autowired
private org.springframework.data.mongodb.core.MongoTemplate template;
Everything fine, so far. Now, if I want to fetch all documents that contain a RealUser, I could call this
template.findAll(RealUser.class)
I'd expect the template to find all documents that have the discriminator property _class set to com.myapp.domain.RealUser.
But this doesn't work as expected. I even get all VirtualUsers, as well, put into objects of type RealUser with all VirtualUser-specific properties missing, and all RealUser-specific properties set to null.
Furthermore, when I go and save a User, which is actually a VirtualUser in MongoDB, but has been squeezed into a RealUser class, Spring would change the _class-property to the wrong type, magically converting a VirtualUser into a RealUser.
So both methods here would load the entire collection and squeeze all objects into the specified class, even if it is the wrong one:
template.findAll(VirtualUser.class)
template.findAll(RealUser.class)
This behavior is probably not desired, or if so, then it is extremely misleading and harmful. You can easily shred your whole data with this.
Can anyone shed some light on this?
I've created a ticket at Spring's Jira. Find Olivers comment below:
The method actually works as expected but I agree that we need to
improve the JavaDoc. The method is basically specified as "Load the
documents the given type is configured to persisted in and map all of
them (hence the name) to the given type". The type given to it is not
used as a type mapping criteria at the same time. Every restriction
you want to apply on the documents returned needs to be applied
through a Query instance, which exposes a ….restrict(…) method that
allows to only select documents that carry type information.
The reason that findAll works the way it works is that generally
speaking – i.e. without an inheritance scenario in place – we need to
be able to read all documents, even if they don't carry any type
information. Assume a collection with documents representing people
that have not been written using Spring Data. If a
findAll(Person.class) applied type restrictions, the call would return
no documents even if there were documents present. Unfortunately we
don't know if the collection about to be queried carries type
information. In fact, some documents might carry type information,
some might not. The only way to reasonably control this, is to let the
user decide, which she can by either calling Query.restrict(…) or not.
The former selects documents with type information only, the latter.
As I said, I totally see that the JavaDoc might be misleading here.
I'm gonna use this ticket to improve on that. Would love to hear if
the usage of Query.restict(…) allows you to achieve what you want.
in hibernate to create criteria we use
Criteria criterea=session.createCritera(SomeClass.class)
It may be available in some other examples too but I am not able to understand the structure of these type of methods.
NOTE this is an example I am trying to put to understand use of SomeClass.class like arguments
my question here is what is purpose of SomeClass.class ? why do we need it, what is the advantages of using it as argument.
Edit its not a duplicate but have string connection to this question
What is this .class syntax?
If you attach .class to the end of a class name, you get the Class<T> object corresponding to the class.
Examples:
String.class returns an instance of Class<String>
Integer.class returns an instance of Class<Integer>
What can you do with a class object
Reflection! If you have access to a class object, you can do all kinds of cool stuff! You can call methods, get and set values of fields...
Why is this used in Hibernate?
I haven't used hibernate before, but this syntax is used in other libraries as well, especially in ORMs or JSON serializers. I'll use JSON serializers as an example as I'm more familiar with those.
In a JSON serializer, you need to give it a class object because it needs to get all the fields that you want to serialize to JSON. It uses reflection to get and set the values of those fields, then convert them to JSON. When it deserializes JSON, it finds the field that needs to be set with the name in the JSON. These operations require a Class object because without it, how can Java know which class should it find the field? Also, to create a new object with reflection, a Class is needed as well!
Hibernate provides many ways to handle the objects in relation with RDBMS tables.
One way is Session interface providing createCriteria() method which can be used to create a Criteria object.
As name says criteria, it is useful to execute queries by applying filtration rules and logical conditions of programmer wish.
For example:
Criteria obj=session.createCritera(Galaxy.class) // say SomeClass is Galaxy.class
List results = obj.list();
Here, criteria query is one which will simply return every object that corresponds to the Galaxy class.
We even can restrict the results with criteria, example add() method available for Criteria object to add restriction for a criteria query.
Following is the restriction to return the records with planet which has 7.4 billion population from Galaxy class:
Criteria cr = session.createCriteria(Galaxy.class);
cr.add(Restrictions.eq(“planet”, 75000000000));
List results = cr.list();
I'm using named queries to fetch entities from a database using JPA and Hibernate and I came across something that was puzzling me: how come there a no default implementations of the javax.persistence.Parameter interface?
I was rather impressed by how #StaticMetamodel is used by CriteriaBuilder in JPA2 meaning that I get Type safety and don't have to mess around with setting string for names. I wanted to apply something similar to some of the JPA1 EJB's that I'm currently working on:
Dealergroup_.class:
public Dealergroup_
{
public Parameter<Integer> id = new ParameterImpl<Integer>("id");
/// etc...
}
DealergroupFacade.class:
// ...
public Dealergroup fetch(Integer id)
{
TypedQuery<Dealergroup> query = em.createNamedQuery("Dealergroup.fetchById", Dealergroup.class);
query.setParameter(Dealergroup_.id, query);
return query.getSingleResult();
}
// ...
I was surprised to find that there were no implementations of the Parameter interface - of course, I could easily implement it myself by their absence makes me suspicious that it may be a mistake to be using it in this way?
Should I be implementing Parameter? Any ideas why there isn't a readily available implementation and why I can't find many (any, really) examples of its use?
That is an interface that a JPA implementation will implement with their implementation of Criteria "ParameterExpression" (which extends Parameter), using their own implementation class. A user goes via CriteriaBuilder.parameter() to get hold of one, or via Query.getParameter() when one is defined by traditional means in the query