I have a question about the #Query annotation that I am using with Spring CrudRepository.
Repository example
public interface DataRepository extends CrudRepository<Entity, Long> {
#Query("WITH $param as param.......")
List<Entity> getByQuery(params...);
}
this service is working fine, but the query String is a huge query and I want to keep it in the resources folder as /resources/query/getEntities.cypher
Can someone help me to understand how to load a query from the resources and populate the query string to the #Query annotation. I remember that it's possible with JPA namedQuery, but here I do not have this dependencies
I want this code to be like this:
public interface DataRepository extends CrudRepository<Entity, Long> {
#Query("/resources/query/getEntities.cypher")
List<Entity> getByQuery(params...);
}
I've tried to create a BeanPostProcess with spring and dynamically update the #Query annotation but getting some errors because of it's a Proxy objects everywhere in the Spring beans implementations
I've tried this:
Query query = AnnotationUtils.findAnnotation(method,Query.class);
then I am not able to get the fields from query as it's a proxies
Thanks in advance
Related
I use Spring Boot Data REST, yes, I write something like below:
#RepositoryRestResource
public interface ExerciseRepository extends JpaRepository<Exercise, Integer> {}
then I open 127.0.0.1/exercises. It will show all exercises.
But I want only show some appointed exercises(eg. exercise id < 100, or other complicated logic) on the 127.0.0.1/exercises.
I know I can use #RestController, but how can I do this with Spring Boot Data REST?
#RepositoryRestResource(path="exercises",collectionResourceRel = "exercises")
can you edit this according to your own code ? I think this will work for you
You can declare an interface method, for example:
#RepositoryRestResource
public interface ExerciseRepository extends JpaRepository<Exercise, Integer> {
List<Exercise> findByIdLessThan(#Param("id") Integer id);
}
In this case, the query is derived from the method name directly, but you can also write a query manually using #Query, for more details check the documentation.
To invoke the method use the following API request:
GET http://localhost:8080/exercises/search/findByIdLessThan?id=100
For reference, Spring Data REST - Useful notes.
EDIT:
If you use Hibernate as your persistence provider, you can use #Where for static filtering, and #Filter for dynamic filtering where filters are defined and configured at runtime, according to Hibernate User Guide.
For example, you can annotate the entity with #Where and define a condition that will be applied to all queries related to that entity:
#Where(clause = "id<100")
#Entity
public class Exercise{
//...
}
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 am not so into Spring Data JPA and I have the following problem working on a Spring Boot project.
I have the following architectural doubt about how to correctly handle this kind of situation:
I have a repository implemented by an interface like this in which I am defining my "query methods":
public interface ExcelRepository extends CrudRepository<Country, Integer> {
public List<Country> findAllByOrderByCountryNameAsc();
public List<BlockAttackDetail> findAllByOrderByAttackTypeAcronymAsc();
}
As you can see I am extending the CrudRepository interface and I specified a single model class named Country mapping a specific table on my database.
I added a second method working on another entity class (BlockAttackDetail) mapping a different database table.
So starting my application I obtain this error because this repository is intended only for the database table mapped by the Country entity class:
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property attackTypeAcronym found for type Country!
My problem is: Do I have to create multiple JPA repositories interfaces (one for each entity) or exist a way to have a single JPA repository interface working on multiple entity classes?
In my specific case I will have few methods that will interact with a specific datbase table (with an entity) and I prefear have a single repository interface handling multiple entity classes (to avoid confusion).
Can I do it in some way? And if I can do it make it sense from an architectural point of view or it is better have a specific JPA repository interface for each entity class?
According to Spring Data documentation you should have one repository for each entity
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.definition
In your case the only way to do your job is with Spring Data JPA:
public interface CountryRepository extends CrudRepository<Country, Integer> {
public List<Country> findAllByOrderByCountryNameAsc();
}
public interface BlockAttackDetailRepository extends CrudRepository<BlockAttackDetail, Integer> {
public List<BlockAttackDetail> findAllByOrderByAttackTypeAcronymAsc();
}
I am trying to stream in an entire database (about 22,000 records) via Spring JPA. Using the FindAll() method I can get them in, but they are all brought into memory at once. I want to stream them.
I have tried streamAll():
#Repository
public interface GroupJsonRepository extends CrudRepository<GroupJson, String> {
Stream<GroupJson> streamAll();
}
but I get a bizarre error:
No property streamAll found for type GroupJson!
My object is:
#Entity
#Table(name = "GroupJson")
public class GroupJson {
#Id
private String id;
private String hash;
private String jsonData;
private ZonedDateTime lastUpdatedTimeStamp;
...
Is there another repository I can use that does this? I can only find CrudRepository. OR, is there some other magic JPA key words that work? I am using Spring boot 1.5.9 and I am streaming data elsewhere, but I am using a custom call:
Stream<Authority> findByPartitionKey(Long partitionKey);
You can use query if too,
#Query("select gj from Customer gj")
Stream<GroupJson> streamAll();
You have to include the "By" part in the method declaration to enable Spring Data to parse your method name. Thats the reason why you get your strange error. Spring Data interprets streamAll as a property in your entity.
#Repository
public interface GroupJsonRepository extends CrudRepository<GroupJson, String> {
Stream<GroupJson> streamAllBy();
}