How to use #Query annotation - java

I am trying to use the #Query to create a custom method in my jpa repository but I am getting the following error at runtime, please help me check it out. Thanks in advance
below is the code
public interface OrganizationRepository extends JpaRepository<Organization, Long> {
List<Organization> findByDeleted(Boolean isDeleted);
List<Organization> findAllByDeletedOrderById(Boolean isDeleted);
#Query(value="SELECT * FROM ORGANIZATION WHERE id = :organizationId AND NAME LIKE %:organizationId% LIMIT 1 ", nativeQuery = true)
Organization findFirstNameByNameLike(#Param("organizationId") Long organizationId, #Param("name") String name);
}
below is the runtime error
Caused by: java.lang.IllegalStateException: Using named parameters for method public abstract com.oasis.firsbacklogbackend.entity.Organization com.oasis.firsbacklogbackend.repository.OrganizationRepository.findFirstNameByNameLike(java.lang.Long,java.lang.String) but parameter 'Optional[name]' not found in annotated query 'SELECT * FROM ORGANIZATION WHERE id = :organizationId AND NAME LIKE %:organizationId% LIMIT 1 '!
I would appreciate any help

You used organizationId twice instead of name. Like this instead:
#Query(value="SELECT * FROM ORGANIZATION WHERE id = :organizationId AND NAME LIKE %:name% LIMIT 1 ", nativeQuery = true)

Related

How to pass path variable to JPA repository from controller

How to pass path variable to JPA repository from controller.
I have a controller here and from the front End I am getting one varaible.
here is my controller :
#GetMapping("/getTransictionsAndInstruments/{id}")
public List<TransictionProjection> getTransitionInstrument(#PathVariable Long id){
return transictionrepository.getTransictionsAndInstruments();
}
Based on this id i want some alteration in my reult. I ahve already have on query and want to use this id in repo. so how to pass that in repo.
#Repository
public interface TransictionRepository extends JpaRepository<Transictions, Long>{
#Query(value = "SELECT transiction.user_id, transiction.quantity, transiction.instrument_name, transiction.Price, instrument.LTP, instrument.jo_caps FROM instrument INNER JOIN transiction ON instrument.instrument = transiction.instrument_name where transiction.User= id", nativeQuery = true)
List<TransictionProjection> getTransictionsAndInstruments();
}
I want to include this line in my query where transiction.User= id
Any help here that how to achive this.
I think this can be achieved by following:
Adding :id in your native query and passing id in function.
#Query(value = "SELECT transiction.user_id, transiction.quantity, transiction.instrument_name,
transiction.Price, instrument.LTP, instrument.jo_caps FROM instrument INNER JOIN transiction ON instrument.instrument = transiction.instrument_name
where transiction.User= :id", nativeQuery = true)
List<TransictionProjection> getTransictionsAndInstruments(Long id);

Spring Data JPA - Creating custom query method generator

In Spring Data JPA we can define a repository interface extending Repository and write a custom method.
If this method follows special syntax, Spring Data will generate the method body automatically.
For example (from the documentation):
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLastname(String lastname);
}
Is there a way to customize the method generation code to introduce new keywords into the syntax?
For example:
Person findExactlyOneById(Long id);
This method would either return the entity or throw a custom exception.
I know I can customize specific repositories as well as the base repository and achieve the effect from the above example, but I'm specifically asking for the automatic method of body generation.
Is there an extension point designed in the framework? Or is the only option to change the source code?
In your case, you can always use CrudRepository.findById(Long id) or JpaRepository.getOne(Long id).
I would suggest inheriting from the JpaRepository class because all types of repositories are included.
You can set nativeQuery = true in the #Query annotation from a Repository class like this:
public static final String FIND_PROJECTS = "SELECT projectId, projectName FROM projects";
#Query(value = FIND_PROJECTS, nativeQuery = true)
public List<Object[]> findProjects();
It's probably worth looking at the Spring data docs as well.
Some more example
1.
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}

Could not extract ResultSet when performing customized native query

I am using Spring Data JPA and I want to encapsulate a method which performs specific SQL. I do it in the following matter:
#Component
public interface UserRepository extends CrudRepository<User, String> {
#Query(
value = "delete from User u where u.alias = :alias",
nativeQuery = true
)
void deleteUserByAlias(#Param("alias") String alias);
}
However, I got the following message as the result:
{
"timestamp": "2018-12-11T15:54:54.627+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet",
"path": "/user/delete"
}
So where is the problem?
If your method is already Transactional , then please use transactional on repository method also
#Component
public interface UserRepository extends CrudRepository<User, String> {
#Query(
value = "delete from User u where u.alias = :alias",
nativeQuery = true
)
#Modifying
#Transactional
void deleteUserByAlias(#Param("alias") String alias);
}
#Repository
#Transactional
interface OrderRepository: JpaRepository<Order, OrderIdentity>{
#Query("SELECT * FROM orders WHERE id=:id",nativeQuery = true)
fun findBy(#Param("id") id: String): List<OrderEvent>
#Modifying
#Query("DELETE FROM orders WHERE id=:id", nativeQuery = true)
fun deleteFor(#Param("id") id: String)
}
By using #Modifying on method and #Transactional on Repository error will be resolved.
your class should be like this:
#Component
public interface UserRepository extends CrudRepository<User, String> {
#Query(
value = "delete from User u where u.alias = :alias",
nativeQuery = true
)
#Modifying
void deleteUserByAlias(#Param("alias") String alias);
}
As you can see I am using #Modifying, for more information take a look to this https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.modifying-queries
Not answer my question directly, but found a workaround to remove record based on other attribute but not ID.
According to answer from this thread,
Derivation of delete queries using given method name is supported
starting with version 1.6.0.RC1 of Spring Data JPA. The keywords
remove and delete are supported. As return value one can choose
between the number or a list of removed entities.
Long removeByLastname(String lastname);
List deleteByLastname(String lastname);
I can write
#Transactional
void deleteByAlias(String alias);
at UserRepository to achieve the goal.
I won't accept this answer and open for any further contribution.
Check the param you are passing is not null. it worked for me.

Spring Pageable does not translate #Column name

I have Entity object :
#Entity(name = "table")
public class SomeEntity {
#Id
#Column(name = "id_column_name")
public final BigDecimal entityId;
#Column(name = "table_column_name")
public final String entityFieldName;
}
And I have database view defined like this:
CREATE OR REPLACE FORCE EDITIONABLE VIEW "V_TABLE" ("ID_COLUMN_NAME", "TABLE_COLUMN_NAME", "SOME_OTHER_COLUMN") AS ... (some SQL magic)
And I have repository with custom query:
#RepositoryRestResource
interface SomeEntityRepository extends PagingAndSortingRepository<SomeEntity, BigDecimal> {
#Query(value = "select id_column_name, table_column_name FROM V_TABLE where some_other_column = ?#{#parameter} order by ?#{#pageable}",
countQuery = "SELECT count(*) from V_TABLE v where some_other_column = ?#{#parameter}",
nativeQuery = true)
Page<SomeEntity> findBySomeParameter(#Param("parameter") long parameter, Pageable pageable);
}
Everything works fine when I request standard data with url:
http://localhost:8080/someEntity/search/findBySomeParameter?parameter=25&page=0&size=20
But when I add sorting information it doesn't work:
http://localhost:8080/someEntity/search/findBySomeParameter?parameter=25&page=0&size=20&sort=entityFieldName,asc
will throw following exception (I'm using Oracle database):
Caused by: java.sql.SQLSyntaxErrorException: ORA-00904: "ENTITYFIELDNAME": invalid identifier
It seems like sorting field are not translated with #Column(name), but are inlined into SQL query.
Is there any way to make pageable sort translated, so that it will use not field name but column name?
This article sheds light on the issue. Read from section 3.1 on.
Apparently dynamic sorting is not supported for native queries. Actually, if you change your findBySomeParameter method to take a Sort instead of a Pageable you will get org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException: Cannot use native queries with dynamic sorting.
Using pageable you don't get the exception, and pagination actually seems to work fine, but dynamic sorting does not substitute the column name as you found. Looks to me like the only solution is to use JPQL instead of native query, which is not a problem as long as the query you need to make is the one you provide. You would need to map the view though to a SomeEntityView class in order to use JPQL.
EDIT
I thought the issue was not documented but it actually is here in the official doc
Spring Data JPA does not currently support dynamic sorting for native queries, because it would have to manipulate the actual query declared, which it cannot do reliably for native SQL. You can, however, use native queries for pagination by specifying the count query yourself, as shown in the following example:
This workaround works for me in SpringBoot 2.4.3:
#PersistenceContext
private EntityManager entityManager;
// an object ptoperty name to a column name adapter
private Pageable adaptSortColumnNames(Pageable pageable) {
if (pageable.getSort().isSorted()) {
SessionFactory sessionFactory;
if (entityManager == null || (sessionFactory = entityManager.getEntityManagerFactory().unwrap(SessionFactory.class)) == null)
return pageable;
AbstractEntityPersister persister = (AbstractEntityPersister) ((MetamodelImplementor) sessionFactory.getMetamodel()).entityPersister(CommentEntity.class);
Sort adaptedSort = pageable.getSort().get().limit(1).map(order -> {
String propertyName = order.getProperty();
String columnName = persister.getPropertyColumnNames(propertyName)[0];
return Sort.by(order.getDirection(), columnName);
}).findFirst().get();
return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), adaptedSort);
}
return pageable;
}
#GetMapping()
public ResponseEntity<PagedResponse<CommentResponse>> findByTextContainingFts(#RequestParam(value = "text", required = false) String text, Pageable pageable) {
// apply this adapter in controller
pageable = adaptSortColumnNames(pageable);
Page<CommentEntity> page = commentRepository.find(text, pageable);
return ResponseEntity.ok().body(domainMapper.fromPageToPagedResponse(page));
}

Spring Data JPA how to pass a variable by using #repository

Thank U, guys! I have found the solution:
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query(value = "select * from Book where find_in_set(:market,market)", nativeQuery = true)
public List<Book> findBooksByMarcket(#Param("market") String market);
}
Original question
I'm using the #Query annotation to create queries by using the JPA query language and to bind these queries directly to the methods of my repository interface.
My database is created correctly and I'm successful to create some queries except this one:
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query("select b from Book b where find_in_set(:market,b.market)")
public List<Book> findBooksByMarcket(#Param("market") String market);
}
I can get the correct result by using the find_in_set function when I check it though MySql. But I cannot reach to pass a variable in java. I have searched though the internet but I cannot find the correct format for it.
please help and thank you guys!
A quick solution is to transform the JPQL query to a native query (by setting the nativeQuery flag to true):
#Query(value = "select * from Book b where find_in_set(:market,b.market)", nativeQuery = true)
public List<Book> findBooksByMarcket(#Param("market") String market);
If you have a custom MySQL function and want to utilize it in a JPA repository, please take a look at tip 1
There is another way to do it using CriteriaBuilder (I used this mechanism along with JPA specification): tip 2
Key words for your search: custom db function, JPA specification, CriteriaBuilder, Criteria
Try this
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query("select b from Book b where find_in_set(?1,b.market)")
public List<Book> findBooksByMarcket(String market);
}

Categories