I'm new to Spring data JPA and am trying to understand how to best use it with QueryDSL. Without QueryDSL, I would be able to simply create any queries in my SpringData interface with an #Query annotation.
In order to have the same experience using QueryDSL, from what I can see, I need to either create my own custom repository implementation and have my repo interface extend my custom implementation interface or put all my QueryDSL queries at a service layer which wraps my repo.
In the first case, I lose the ability to use any of the SD autogenerated methods (ex: findAll(QueryDSL predicate) ) in my custom repo since I don't have access to the actual repo object, and in the second case I am putting query logic at the service layer instead of at the repo layer.
Neither solution sounds particularly attractive to me. Is there a 3rd way that is more appropriate? Or am I misunderstanding how to properly use QueryDSL and Spring Data?
Thanks!
Eric
Probably the most convenient way is to let your repository interfaces simply extend QueryDslPredicateExecutor which adds the capability to simply pipe Querydsl Predicate objects into the repository and execute them standalone or alongside Pageable and Sort and the like.
If you really want to hide the combination of predicates into the repository layer (which is absolutely fine but actually serves a different purpose) you create a separate repository implementation class as described here and use QueryDslRepositorySupport as base class. In your implemented finder methods you can then just use the from(…), update(…) and delete(…) methods of the base class to easily construct and execute queries using the Querydsl meta-model.
Related
I am looking into Spring data and one thing I've noticed is that we're able to perform CRUD operations just by creating an interface which implements the CRUD repository and by default, we're given access to generated queieres to the db via the method name.
I thought whenever we implement an Interface, we need to provide an implementation to the methods. So why don't we override anything when we use an interface which implements from the CrudRepository interface?
One of the goals of Spring Data is to make database access easy, without the need to manually write a lot of boilerplate code.
Traditionally, one of the things developers commonly did when working with a database is write DAOs (database access objects) with methods, where each method would do a specific query. Such methods would typically be boilerplate code - simple, repetitive code that's a lot of work to write and maintain and that doesn't contain any business logic.
When you use Spring Data, all this code is automatically generated for you. The only thing you have to do is specify in a repository interface what query you want to do, and Spring Data then interprets the meaning of the method name to automatically generate the code that does the query for you.
That saves you a lot of time and helps you a great deal to keep your own code concise; it also helps with the prevention of bugs.
The implementation of a Spring Data repository interface is generated automatically at runtime. This isn't done by generating source code which is compiled - behind the scenes Spring Data directly generates the bytecode of the implementation of the interface.
I am planning to use PagingAndSortingRepository interface methods and wanted to understand how do we specify what query to run on calling the method such as findAll?
I'm assuming JPA, but other stores work the same or in case of annotating the entity model similar.
Normally you don't. Spring Data figures out these queries on your behalf. If you want a different query to be executed than the one Spring Data picks, you have the usual choices for custom methods in Spring Data:
If you only need to change table or column names you can annotate your entity model.
provide a #Query annotation.
provide a complete custom annotation.
I have been working with Spring Data JPA repository in my project for some time and I know the below points:
In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object).
Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).
I am interested on how this has been coded and I have looked at the Spring JPA source code & APIs, but I could not find answers to the questions below:
How is the repository implementation class generated at runtime & methods being implemented and injected?
Does Spring Data JPA use CGlib or any bytecode manipulation libraries to implement the methods and inject dynamically?
Could you please help with the above queries and also provide any supported documentation ?
First of all, there's no code generation going on, which means: no CGLib, no byte-code generation at all. The fundamental approach is that a JDK proxy instance is created programmatically using Spring's ProxyFactory API to back the interface and a MethodInterceptor intercepts all calls to the instance and routes the method into the appropriate places:
If the repository has been initialized with a custom implementation part (see that part of the reference documentation for details), and the method invoked is implemented in that class, the call is routed there.
If the method is a query method (see DefaultRepositoryInformation for how that is determined), the store specific query execution mechanism kicks in and executes the query determined to be executed for that method at startup. For that a resolution mechanism is in place that tries to identify explicitly declared queries in various places (using #Query on the method, JPA named queries) eventually falling back to query derivation from the method name. For the query mechanism detection, see JpaQueryLookupStrategy. The parsing logic for the query derivation can be found in PartTree. The store specific translation into an actual query can be seen e.g. in JpaQueryCreator.
If none of the above apply the method executed has to be one implemented by a store-specific repository base class (SimpleJpaRepository in case of JPA) and the call is routed into an instance of that.
The method interceptor implementing that routing logic is QueryExecutorMethodInterceptor, the high level routing logic can be found here.
The creation of those proxies is encapsulated into a standard Java based Factory pattern implementation. The high-level proxy creation can be found in RepositoryFactorySupport. The store-specific implementations then add the necessary infrastructure components so that for JPA you can go ahead and just write code like this:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
The reason I mention that explicitly is that it should become clear that, in its core, nothing of that code requires a Spring container to run in the first place. It needs Spring as a library on the classpath (because we prefer to not reinvent the wheel), but is container agnostic in general.
To ease the integration with DI containers we've of course then built integration with Spring Java configuration, an XML namespace, but also a CDI extension, so that Spring Data can be used in plain CDI scenarios.
Actually, I'm new on spring Boot but I've been using Spring for a little while. With spring, I used to handle my database(MySQL) through a generic DAO with hibernate/JPA. However all the tutorials I found on spring Boot use spring data jpa making, therefore, configurations easier.
Thus I would like to know whether it is or not a good idea to keep using my old generic DAO, as it allows me to have the full control and to customize my data access as I want. If yes, how can I proceed? If not, what can be the disadvantages?
The DAO pattern is the same as the Repository Pattern that Spring Data supports. At least, it should be. You have one DAO (=Repository) class per entity that provides methods to query or manipulate that entity.
whether It is or not a good idea to keep using my old generic DAO, as
it allows me to have the a full control and to customize my data
access as I want.
Spring Data is flexible enough to allow full control over your queries. You have the following options (code examples copied from the Spring Data reference):
Using method names: You can simply name your repository methods like this to let Spring Data auto-generate a query for you:
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
Using custom queries per annotation: Provide a custom JPAQL query within a #Query annotation
#Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
Using named queries: define a named JPAQL query within an xml file and reference it within the #Query annotation
<named-query name="User.findByLastname">
<query>select u from User u where u.lastname = ?1</query>
</named-query>
#Query(name="User.findbyLastname")
List<User> findByLastname(String lastname);
Implement a repository method yourself: provide part of the implementation of a Spring Data repository yourself by accessing the Hibernate session (or that of another JPA provider) yourself.
So, to answer your question: yes, use Spring Data JPA, especially on new projects! It does so much work for you and you can still control queries as you wish (which should only be necessary for complicated queries, and even for those I would suggest using programmatic Specifications).
Spring Data JPA will make your life as a developer easier. The DAO pattern is very similar to the Repository Pattern. The advantage of using Spring Data JPA is that you’ll be writing a lot less code. Spring Data JPA works a lot like Spring Integration Gateways, where you define an interface, and Spring provides the implementation at run time.
I have been working with Spring Data JPA repository in my project for some time and I know the below points:
In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object).
Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).
I am interested on how this has been coded and I have looked at the Spring JPA source code & APIs, but I could not find answers to the questions below:
How is the repository implementation class generated at runtime & methods being implemented and injected?
Does Spring Data JPA use CGlib or any bytecode manipulation libraries to implement the methods and inject dynamically?
Could you please help with the above queries and also provide any supported documentation ?
First of all, there's no code generation going on, which means: no CGLib, no byte-code generation at all. The fundamental approach is that a JDK proxy instance is created programmatically using Spring's ProxyFactory API to back the interface and a MethodInterceptor intercepts all calls to the instance and routes the method into the appropriate places:
If the repository has been initialized with a custom implementation part (see that part of the reference documentation for details), and the method invoked is implemented in that class, the call is routed there.
If the method is a query method (see DefaultRepositoryInformation for how that is determined), the store specific query execution mechanism kicks in and executes the query determined to be executed for that method at startup. For that a resolution mechanism is in place that tries to identify explicitly declared queries in various places (using #Query on the method, JPA named queries) eventually falling back to query derivation from the method name. For the query mechanism detection, see JpaQueryLookupStrategy. The parsing logic for the query derivation can be found in PartTree. The store specific translation into an actual query can be seen e.g. in JpaQueryCreator.
If none of the above apply the method executed has to be one implemented by a store-specific repository base class (SimpleJpaRepository in case of JPA) and the call is routed into an instance of that.
The method interceptor implementing that routing logic is QueryExecutorMethodInterceptor, the high level routing logic can be found here.
The creation of those proxies is encapsulated into a standard Java based Factory pattern implementation. The high-level proxy creation can be found in RepositoryFactorySupport. The store-specific implementations then add the necessary infrastructure components so that for JPA you can go ahead and just write code like this:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
The reason I mention that explicitly is that it should become clear that, in its core, nothing of that code requires a Spring container to run in the first place. It needs Spring as a library on the classpath (because we prefer to not reinvent the wheel), but is container agnostic in general.
To ease the integration with DI containers we've of course then built integration with Spring Java configuration, an XML namespace, but also a CDI extension, so that Spring Data can be used in plain CDI scenarios.