Spring Boot #Query annotation throwing unexpected token error on the alias - spring-boot

Below is the snippet of the offending code
package com.example.demo.repositories;
import com.example.demo.models.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.Optional;
#Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
#Query("SELECT s FROM Student WHERE s.email = ?1")
Optional<Student> findStudentByEmail(String email);
}
This a piece of the error returned
caused by: org.hibernate.QueryException: Unable to resolve path [s.email], unexpected token [s]...

You missed alias(in your case 's') with the entity name.
so it should be,
#Query("SELECT s FROM Student s WHERE s.email = ?1")
Optional<Student> findStudentByEmail(String email);

#Query("SELECT s FROM Student s WHERE s.email = ?1")
Optional<Student> findStudentByEmail(String email);

There are two ways to do it
As already outlined in the other answers, you missed declaring the alias in the statement. Thus the correct code should be
#Query("SELECT s FROM Student s WHERE s.email = ?1")
Optional<Student> findStudentByEmail(String email);
Alternatively, if your query is simple as the one above, you can try omitting the alias as shown in the below example
#Query("FROM Student WHERE email = ?1")
Optional<Student> findStudentByEmail(String email);

Related

JpaRepository query parameters are not getting updated dynamically

Query parameters are not getting updated -
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.erecruitment.app.model.user;
#Repository
public interface updatePassword extends JpaRepository<user, Long>{
#Transactional
#Modifying
#Query(value="UPDATE user SET password=?1 WHERE username=?2",nativeQuery=true)
int updtPassword(String password,String username);
}
Result upon execution is -
Hibernate:
UPDATE
user
SET
password=?
WHERE
username=?
I tried hardcoding the parameters like -
#Query(value="UPDATE user SET password='ee' WHERE username='w#g.com'",nativeQuery=true)
And , it worked .But , the first one not worked .Can you please take a minute in helping me , because I am not getting where am I getting wrong?
The above code looks good and worked on my local machine.
Can you please add more details about your question?
Please try:
#Transactional
#Modifying
#Query(value="UPDATE user SET password= :password WHERE username= :username ",nativeQuery=true)
int updtPassword(#Param("password") String password,#Param("username") String username);
Param class to be imported:
import org.springframework.data.repository.query.Param;

Java Spring JPA conversion to myBatis

For homework I was asked to implement myBatis. However, I already started all of my project using Spring Data JPA. And so I need to translate JPA query to myBatis. here is the code in JPA:
follow this link for the code snippet
#Repository
public interface VoteRepository extends JpaRepository<Vote, Long> {
#Query("SELECT NEW com.example.polls.model.ChoiceVoteCount(v.choice.id, count(v.id)) FROM Vote v WHERE v.poll.id in :pollIds GROUP BY v.choice.id")
List<ChoiceVoteCount> countByPollIdInGroupByChoiceId(#Param("pollIds") List<Long> pollIds);
#Query("SELECT NEW com.example.polls.model.ChoiceVoteCount(v.choice.id, count(v.id)) FROM Vote v WHERE v.poll.id = :pollId GROUP BY v.choice.id")
List<ChoiceVoteCount> countByPollIdGroupByChoiceId(#Param("pollId") Long pollId);
#Query("SELECT v FROM Vote v where v.user.id = :userId and v.poll.id in :pollIds")
List<Vote> findByUserIdAndPollIdIn(#Param("userId") Long userId, #Param("pollIds") List<Long> pollIds);
#Query("SELECT v FROM Vote v where v.user.id = :userId and v.poll.id = :pollId")
Vote findByUserIdAndPollId(#Param("userId") Long userId, #Param("pollId") Long pollId);
#Query("SELECT COUNT(v.id) from Vote v where v.user.id = :userId")
long countByUserId(#Param("userId") Long userId);
#Query("SELECT v.poll.id FROM Vote v WHERE v.user.id = :userId")
Page<Long> findVotedPollIdsByUserId(#Param("userId") Long userId, Pageable pageable);
}
I'm trying to use these myBatis imports instead:
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Param;

Ignite CrudRepository still getting name conflict for deleteAll

I using ignite core, and ignite-spring-data both 2.7.0
compile "org.apache.ignite:ignite-core:2.7.0"
compile "org.apache.ignite:ignite-spring-data:2.7.0"
compile('org.springframework.boot:spring-boot-starter-jdbc:2.1.5.RELEASE');
But I still get this error:
error: name clash: deleteAll(Iterable<? extends T>) in CrudRepository and deleteAll(Iterable<ID>) in IgniteRepository have the same erasure, yet neither overrides the other
where T,ID are type-variables:
T extends Object declared in interface CrudRepository
ID extends Serializable declared in interface IgniteRepository
According to https://issues.apache.org/jira/browse/IGNITE-6879 this issue was resolved with version 2.7.0 so why am I still getting it?
if I use instead:
compile "org.apache.ignite:ignite-spring-data_2.0:2.7.0"
It seems to break everything, so I am not sure that an option.
import org.apache.ignite.springdata.repository.IgniteRepository;
import org.apache.ignite.springdata.repository.config.Query;
import org.apache.ignite.springdata.repository.config.RepositoryConfig;
#RepositoryConfig(cacheName = "PersonCache")
public interface PersonRepository extends IgniteRepository<Person, Long> {
List<Person> findByFirstNameAndLastName(String firstName, String lastName);
#Query("SELECT c.* FROM Person p JOIN \"ContactCache\".Contact c ON p.id=c.personId WHERE p.firstName=? and p.lastName=?")
List<Contact> selectContacts(String firstName, String lastName);
#Query("SELECT p.id, p.firstName, p.lastName, c.id, c.type, c.location FROM Person p JOIN \"ContactCache\".Contact c ON p.id=c.personId WHERE p.firstName=? and p.lastName=?")
List<List<?>> selectContacts2(String firstName, String lastName);
}
Just switch to new 2.0 support version of ignite spring data.
compile "org.apache.ignite:ignite-spring-data_2.0:${igniteVersion}"
import org.apache.ignite.springdata20.repository.IgniteRepository;
import org.apache.ignite.springdata20.repository.config.Query;
import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
No worries!
After changing to use:
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-spring-data_2.0</artifactId>
<version>${ignite.version}</version>
</dependency>
.....
<ignite.version>2.7.0</ignite.version>
You will have to re-import everything. so just delete the 'import' part from the code all together. Since now the IgniteRepository etc are coming from a package called org.apache.ignite.springdata20.repository .... instead of the old one.

When using CrudRepository how can I use transformers

I have read this article
https://smarterco.de/spring-data-jpa-query-result-to-dto/
And tried this.
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
#Query("SELECT u FROM User AS u")
List<User> findAll();
#Query("SELECT new de.smarterco.example.dto.UserNameDTO(u.id, u.name) FROM User u WHERE u.name = :name")
List<UserNameDTO> retrieveUsernameAsDTO(#Param("name") String name);
}
And it works.
But lets say my User had a list of Address. And my UserNameDTO also had a corresponding dto. How could I do that?
Can I somehow attach a resultTransformer to the query? or register a converter?
Looking forward to your suggestions.
Best regards. Ole Bille

Data Rest Repository Custom Annotated Query

I'm working my way through the Spring Data-Rest guide and struggling writing a custom annotated query and not sure if it's even possible, here's the code:
CategoryRepository
package com.example.repositories
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.data.rest.core.annotation.RepositoryRestResource
import org.springframework.data.rest.core.annotation.RestResource
import com.example.entities.Category
import com.example.entities.InventoryDetail
#RepositoryRestResource(collectionResourceRel="categories", path="categories")
interface CategoryRepository extends JpaRepository<Category, Long> {
#RestResource(path="inventoryByCategory",rel="inventoryByCategory")
#Query("select new com.example.entities.InventoryDetail(i.id, i.item, c.name) from Category c join c.inventory i where upper(c.name) like upper(:name+'%')")
Page<InventoryDetail> queryByCategoryStartsWithIgnoreCase(#Param("name") String name, Pageable pageable)
}
The query above is the one that I'm struggling with, not sure how to properly do this. I searched for hours looking for a solution but could not find one.
Category Entity
package com.example.entities
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.FetchType
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.JoinColumn
import javax.persistence.OneToMany
import javax.persistence.Table
#Entity
#Table(name="categories")
class Category implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
long id
#Column
String name
#Column
String description
#OneToMany(targetEntity=Inventory.class, fetch=FetchType.LAZY)
#JoinColumn(name="category")
List<Inventory> inventory
}
Inventory Entity
package com.example.entities
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.Index
import javax.persistence.Table
#Entity
#Table(name="inventory", indexes=[ #Index(columnList="category", unique=false) ])
class Inventory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
long id
#Column
long category
#Column
String item
#Column
String description
#Column
long price
#Column
long onHand
}
InventoryDetail
package com.example.entities
import javax.persistence.Column;
class InventoryDetail {
long id
String item
String name
InventoryDetail(long id, String item, String name) {
this.id = id
this.item = item
this.name = name
}
}
If I want to select specific fields from both entities, do I need to have a custom DTO like the one above? Is it possible to just use a new map(...) instead? Either way, the query runs and I see it in the console, but in the HAL browser it gives me a 500 error, I'm sure I am overlooking something, but not sure what it is.
I appreciate your help in advance!
EDIT
Here is the output from the Hibernate query:
Hibernate: select count(category0_.id) as col_0_0_ from categories category0_ inner join inventory inventory1_ on category0_.id=inventory1_.category where upper(category0_.name) like upper(?+'%')
Hibernate: select inventory1_.id as col_0_0_, inventory1_.item as col_1_0_, category0_.name as col_2_0_ from categories category0_ inner join inventory inventory1_ on category0_.id=inventory1_.category where upper(category0_.name) like upper(?+'%') limit ?
After countless hours of testing, I decided to throw the code in a controller and access it via the EntityManager, and it worked. After getting it to work from the controller I realized that JPA/Hibernate is expecting an Entity and not an Object/DTO.
I was able to do this...
List<Object> list(String name) {
def qry = "select new map(i.id as id, i.item as item, c.name as category) from Category c join c.inventory i where upper(c.name) like upper(:name+'%')"
List<Object> results = em.createQuery(qry).setParameter('name',name).getResultList()
return results
}
Your Query :
#Query("select new com.example.entities.InventoryDetail(i.id, i.item, c.name) from Category c join c.inventory i where upper(c.name) like upper(:name+'%')")
In your custom query no join mapping for Category and Inventory. Repace this line of code by following where Category and Inventory mapped by their id in join:
#Query("select new com.example.entities.InventoryDetail(i.id, i.item, c.name) from Category c join c.inventory i where c.id=i.category upper(c.name) like upper(:name+'%')")
Note: by default on jpql join means inner join
I'm not sure if this is the cause of your 500 error, but I see something wrong with your query, particularly with how you concatenate the paramater name with the wildcard character %.
#Query("select new com.example.entities.InventoryDetail(i.id, i.item, c.name) from Category c join c.inventory i where upper(c.name) like upper(:name+'%')")
You must remove the plus sign and the single quotes.
#Query("select new com.example.entities.InventoryDetail(i.id, i.item, c.name) from Category c join c.inventory i where upper(c.name) like upper(:name%)")
See sample implementation here.

Resources