in Spring Data JPA Repository i need to specify multiple methods that do the same thing (eg. findAll) but specifying different #EntityGraph annotation (the goal is to have optimized methods to use in different services).
Es.
#Repository
public interface UserRepository extends JpaSpecificationExecutor<User>, JpaRepository<User, Long> {
#EntityGraph(attributePaths = { "roles" })
findAll[withRoles](Specification sp);
#EntityGraph(attributePaths = { "groups" })
findAll[withGroups](Specification sp);
etc...
}
In Java we can't have same method sign multiple times, so how to manage it?
Is it possible without using JPQL?
Thanks,
Gabriele
You can use EntityGraphJpaSpecificationExecutor to pass different entitygraph based on your method.
#Repository
public interface UserRepository extends JpaSpecificationExecutor<User>, JpaRepository<User, Long>, EntityGraphJpaSpecificationExecutor<User> {
}
In your service class, you can call find all with entity graph.
List<User> users = userRepository.findAll(specification, new NamedEntityGraph(EntityGraphType.FETCH, "graphName"))
Like above, you can use a different entity graph different based on your requirement.
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()
when building respositories in spring, in my repository interface i extend it using the below
extends CrudRepository<EntityName, EntityType> where EntityName is the name of my Entity Class and EntityType is set to default type Long see sample code below
#Repository
public interface RoomRepository extends CrudRepository<Room, Long> {
}
I have noticed however the use of JpaRepository see example below
public interface RoomRepository extends JpaRepository<Room, UUID>{
public Boolean existsRoom(String roomNumber);
}
JpaRepository extends PagingAndSortingRepository which in turn extends CrudRepository.
CrudRepository mainly provides CRUD functions.
PagingAndSortingRepository provides methods to do pagination and sorting
records.
JpaRepository provides some JPA-related methods such as flushing the persistence context and deleting records in a batch.
Because of the inheritance mentioned above, JpaRepository will have all the functions of CrudRepository and PagingAndSortingRepository.
So if you don't need the repository to have the functions provided by JpaRepository and PagingAndSortingRepository, use CrudRepository.
Reference:
https://www.javatpoint.com/spring-boot-crud-operations#:~:text=CrudRepository%20does%20not%20provide%20any,works%20as%20a%20marker%20interface.
I have an entity with a lot of relationships. I cannot change them because the mapping is used in numerous parts of the code.
In only one use case, I would like to be able to load only the entities and not their relationships.
I made a simple CRUDRepository like this :
public interface EmployeeRepository extends CrudRepository<Employee, UUID> {
List<Employee> findByCompanyId(UUID companyId);
}
How can I load Employee without their relationships without altering the mapping annotations?
I tried :
public interface EmployeeRepository extends CrudRepository<Employee, UUID> {
List<Employee> findLazyByCompanyId(UUID companyId);
}
This compiles but the entities are still not lazy loaded. I am surprised that the keyword 'Lazy' is accepted if lazy loading is not done.
Any idea?
There is no easy way. Possibly no way full stop -that would depend on your persistence provider. That is why should mostly define relationships as lazy and load eagerly when required rather than the other way around.
See, for example:
JPA and eclipselink - Overriding FetchType.Eager
and
How to override FetchType.EAGER to be lazy at runtime
All I could suggest would be to use a constructor expression to either return a list of unmanaged users.
http://www.objectdb.com/java/jpa/query/jpql/select#Result_Classes_Constructor_Expressions_
or, more simply use a Spring Data projection to return a subset of the data:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
public interface EmployeeRepository extends CrudRepository<Employee, UUID> {
EmployeeSummaryProjection findByCompanyId(UUID companyId);
}
#Projection(name="EmployeeSummaryProjection", types = {Employee.class})
interface EmployeeSummaryProjection{
/declare methods matching the data you wish to return
}
If the data returned is read-only then either of the above may be a solution.
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
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.