In Spring Data is it possible to turn off Query Generation from method names?
Given the interface
public interface UserRepository extends Repository<User, Long> {
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
I would want spring security to produce an error saying that generating queries from method names has been turned off please use the explicitly #Query annotation like so.
public interface UserRepository extends Repository<User, Long> {
#Query("select u from User u where u.emailAddress = ?1 and u.lastname = ?2")
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
I want to turn off the the automatic query generation because I think it is easier to read the query and know what is going on rather than reading the method name and translating to what is the query that Spring data will generate, also on a large team with lots of developers some who might not yet be familiar with spring data #Query is a lot more readable?
How to turn off Query creation from method names in Spring JPA?
You can specify the query-lookup-strategy on the repositories tag in the configuration.
<repositories query-lookup-strategy="use-declared-query"/>
See the documentation
User.java
#Entity
#NamedQuery(name="User.findByEmailAddressAndLastName",
query="select u from User u where u.emailAddress = ?1 and u.lastname = ?2")
public User{
}
UserRepository.java
public interface UserRepository extends Repository<User, Long> {
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
How Spring handles this is called the Query Lookup Strategy. Queries can be resolved by method names (CREATE), by manual queries (USE_DECLARED_QUERY), or both (CREATE_IF_NOT_FOUND) which defaults to method names if no manual query is found. USE_DECLARED_QUERY would give you the desired functionality, warning you if no manual query is specified.
As Kevin answered, this can be configured in xml. But as a more modern option, you can specify the lookup strategy when configuring your repository in a Java Config class with queryLookupStrategy parameter in the #Enable{store}Repositories annotation.
For example, to force manual queries, you could use the following:
#EnableJpaRepositories(queryLookupStrategy=QueryLookupStrategy.Key.USE_DECLARED_QUERY)
public class MyDatabaseConfig {
...
}
More info here
https://docs.spring.io/spring-data/jpa/docs/2.0.7.RELEASE/reference/html/#repositories.query-methods.query-lookup-strategies
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/query/QueryLookupStrategy.Key.html?is-external=true
Related
I am using Spring Boot application. I am using following method to return List<String> using #Query
annotation.
#Query("select c.name from Customer c")
List<String> findAllNames();
Is there a way to get the above result without #Query or #NativeQuery annotations?
Spring Data JPA supports this quite well. You can define a POJO that represents the (reduced) object (the projection) you want of the entity, then define a method that describes the query, returns the appropriate type, and Spring Data will generate all the code necessary to execute the query and map the results.
Here's an example of a custom repository interface that uses this technique (untested pseudo-code):
public class CustomerSummary {
private String name;
// constructor and getters
}
#Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<CustomerSummary> getAllSummaries();
}
I'm not sure if you can use "simple" types such as String in the return type, but I wouldn't be surprised if that is supported.
Also, you might have to tweak the exact method naming of `` to make sure Spring Data correctly interprets it as you want. Here is some additional reference documentation.
You could use projection to select only name property:
interface CustomerNameProjection {
String getName();
}
and then use it in Repository class:
List<CustomerNameProjection> findAllProjectedBy();
edit: corrected repository method name
Inject EntityManager and call createQuery.
entityManager.createQuery("select c.name from Customer c")
.getResultList()
I'm in the process of migrating a spring boot application to micronaut and stumbled upon a problem with micronaut data.
When using native queries which worked in spring boot data I get a compilation error for a query in which I try to insert some data into associative table.
Unable to implement Repository method: MyEntityRepository.insertQueryExample(int id, String name). No possible implementations found.
Other native queries (selects, deletes) work no problem, same goes for generated methods.
Here's how the repo with said method looks like:
public interface MyEntityRepository extends CrudRepository<MyEntity, Integer> {
#Query(value = "insert into my_entity_my_entity2 (id, id2)" +
" values (:id, (select me2.id from my_entity2 os where me2.name = :name))", nativeQuery = true)
void insertQueryExample(int id, String name);
}
There's no entity class for my_entity_my_entity2 but that worked in spring so I don't think that's a problem.
Thanks in advance for your help.
There's no entity class for my_entity_my_entity2 but that worked in spring so I don't think that's a problem.
Indeed, this is the issue.
All io.micronaut.data.repository.GenericRepository expects a respective entity type (which must be introspected, would it be the Micronaut Data JPA or Micronaut Data JDBC implementation.
The solution you are left with is to implement a custom JpaRepository sub-type and use either the injected EntityManager or JpaRepositoryOperations to perform custom query execution while retaining default intercepted methods:
#Repository
public abstract class MyEntityRepository implements CrudRepository < MyEntity, Integer> {
#Inject
JpaRepositoryOperations operations;
#Transactional
void insertQueryExample(int id, String name) {
operations.getCurrentEntityManager()
.createNativeQuery("insert into my_entity_my_entity2 (id, id2)" +
" values (:id, (select os.id from my_entity2 os where os.name = :name))")
.setParameter("id", id)
.setParameter("name", name)
.executeUpdate();
}
}
You can then inject your MyEntityRepository bean and invoke your custom query method.
I want to write a finder method in my repository to find an object based on one field OR another one while supplying one parameter like:
#RepositoryDefinition(domainClass = Person.class, idClass = Long.class)
public interface PersonRepository extends CrudRepository<Person, Long> {
List<Person> findAllByIdOrAnotherId(someId);
}
How can I do that without using SQL?
I added a second parameter to the method and it worked.
List<Transaction> findAllByIdOrParentId(Long id, Long parentId);
This is just a definition for the method because I pass the same parameter to the method from the service as:
List<Transaction> transactions = transactionRepository.findAllByIdOrParentId(transactionId, transactionId);
One of the cool things about Spring Data JPA is the fact you can define custom queries as abstract methods in your interface.
In a nutshell, you can define a new search criteria just by specifying the #Entity field name you want to query by. So, let's say i want to findAll() by Id and CustomId. Both Id and CustomId are fields on my domain class. I would do:
List<Person> findAllByIdOrCustomId(someId, someCustomId);
For more info, research the link below:
Spring Data JPA - DEFINE QUERY METHODS
I was wondering if there was a way using JPA query (not sure what the word I'm looking for is sorry).
#Transactional
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastNameIgnoreCase(String lastName); //This is the format I am looking for
#Query("SELECT DISTINCT t.lastName FROM User t") //Don't want to have to use the #Query
List<String> findDistinctLastNames();
}
Hopefully that makes it more clear. But I am trying to perform that Query without having to use the #Query. It doesn't really affect anything having it there, I would just like it. Is that statement possible?
Spring Data JPA uses reflection to match method signatures to field names and operations so confirming you have the correct column name would be a good place to start, i.e. is it lastName or lastNames?
Otherwise, according to the Spring Data JPA documentation, the following should work correctly:
List<User> findDistinctByLastName(String lastName);
Are you getting a stack trace?
For example, I have entity User with fields id, active and 10 more.
How could I get all active Users? Easy:
public interface UserRepository extends JpaRepository<User, Integer> {
List<User> findAllByActiveTrue();
}
How could I load list of id of active users? I need a #Query annotation to write JPQL by myself, like this:
public interface UserRepository extends JpaRepository<User, Integer> {
#Query("select u.id from User u where u.active = true")
List<Integer> fetchActiveUsersIds();
}
My question is: could I name somehow a method to avoid writing JQPL by myself, like in first case?
UPDATE
I need something like this:
public interface UserRepository extends JpaRepository<User, Integer> {
List<Integer> findAll_Id_ByActiveTrue();
}
I think that is not possible. The main purpose of Repositoryis to manage persistence of Domain Classes. It doesn't manage the properties independently. In the Spring Data Repositories documentation you can find a list of the methods available for CrudRepository.
You can compose your query using property extensions but it always returns the domain class for non aggregated methods.
For the specific use case you mention you'll need to use the #Query annotation.