Can we fetch data using JPA without using primary key - spring

My Table:
Emotion
EID (Primary Key)
user_mood
Latitude
Longitude
uid
#Entity
public class Emotion
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer eId;
#Column(name = "user_mood")
private String mood;
private String latitude;
private String longitude;
private String uid;
}
My Interface:
public interface EmotionRepository extends JpaRepository<Emotion, String>{}
When I try to fetch values using uid
emotionRepo.findById(uid)
I am getting below type mismatch error
Error message:
org.hibernate.TypeMismatchException: Provided id of the wrong type for class mood_sensor.mood_sensor.pojos.Emotion. Expected: class java.lang.Integer, got class java.lang.String
Can I retrieve data using uid or I should use only the primaryKey(Integer) to retrieve data?

Yes, it's possible, but the method findById, from CrudRepository<T, ID> always expect to receive the ID as the argument - see here (be aware that JpaRepository extends from CrudRepository).
You can query by another field in a variety of ways, but as I saw that your use case is pretty simple, I'd suggest you to make use of Spring Data's query creation deriving from the method's name - see here and here
It's really simple, just create a method called findByUid in your EmotionRepository and Spring will take care of the rest by deriving the desired query from the method's name:
public interface EmotionRepository extends JpaRepository<Emotion, Integer> {
Optional<Emotion> findByUid(String uid);
}
Spring Data will then generate something like the following query:
SELECT e.* FROM Emotion e WHERE e.uid = <the-value>
Now, you can use findByUid method to query using the uid field.
And another fix: change from
EmotionRepository extends JpaRepository<Emotion, String>
to
EmotionRepository extends JpaRepository<Emotion, Integer>
this is because the id from Emotion is of type Integer, not String.

Inside your JpaRepository (EmotionRepository), you can make a function signature, anmd and the JPA will create a method to fetch whatever data you need.
This doc should help you understand exactly what is happening: http://static.springsource.org/spring-data/data-jpa/docs/1.0.0.M1/reference/html/#jpa.query-methods.query-creation

Related

CRUDRepository findBy foreign key id causing exception: Unable to locate Attribute with the the given name [classroomId] on this ManagedType

I am getting an exception when creating a custom findBy method by a foreign key.
Entity class:
#Entity
#Getter
#Setter
public class Thread {
private #Id #GeneratedValue Long id;
private String subject;
#ManyToOne(fetch = FetchType.LAZY)
#JsonIgnore
private Classroom classroom;
protected Thread() {}
public Long getClassroomId() {
return this.classroom.getId();
}
}
ThreadRepository class:
public interface ThreadRepository extends CrudRepository<Thread, Long> {
List<Thread> findByClassroomId(Long id);
}
I get the exception:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [classroomId] on this ManagedType [com.futurerprood.unicycleservice.entity.threads.Thread]
But the exception goes away if I remove the getClassroomId() in the Thread class. I have this function so that the json serialization will pick up only the classroom id instead of the whole classroom object in an endpoint response.
Why is this function causing the foreign key unable to be found?
You can do one of the following:
Provide the query to the repository method
#Query("select e from Thread t join t.classroom c where c.id = :id")
List<Thread> findByClassroomId(Long id);
Rename the repository method
List<Event> findByClassroom_Id(Long id);
Update
Explanation as to why these two are working
First, have a look at https://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/htmlsingle/#d0e391 and understand how property traversal based on method name happens in Spring data JPA in order to generate the query and how ambiguity resolution is recommended.
In the first one, we tell spring data, it does not need to do property traversal to generate the JPA query as we are giving the query so it does not get any ambiguity.
In the second, as recommended in the reference, we are resolving the ambiguity for Spring Data JPA by telling it to go to Classroom object first. But as #crizzis pointed out under the question comment, Spring data should have treated it as ambiguity in the first place

Spring data jpa search filter by foreign key and type

Model Class Vehicle
#Column(name="type",nullable=false)
private String type;
#Column(name="last_service_date",nullable=false)
private String lastServiceDate;
#Column(name="seats",nullable=false)
private Long seats;
#Column(name="bags_capacity",nullable=false)
private Long bagsCapacity;
#Column(name="milage",nullable=false)
private Long milage;
//for Franchise object id
private transient Long fId;
#ManyToOne
#JoinColumn(name="franchise_id")
private Franchise fkFranchiseId;
#Repository
public interface VehicleRepository extends JpaRepository<Vehicle,Long>
{
}
I am using spring data jpa repositories and want to search Vehicle by type and foreignKey=>(zipcode) how can i find
Just add a method in your Vehicle JPA repository interface as follow:
findAllByTypeAndFkFranchiseIdZipCode(String type, String zipCode);
And also you are welcome to check docs of Spring Data Jpa
List<Vehicle> findAllByTypeAndFkFranchiseId_ZipCode(String type, String zipCode);
You can use JPA repo method name query documented here https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
public interface VehicleRepo extends JpaRepository<Vehicle, String> {
List<Vehicle> findAllByTypeAndFkFranchiseIdZipCode((String type, String zipCode);
Page<Vehicle> findAllByTypeAndFkFranchiseIdZipCode((String type, String zipCode,Pageable page);
}
for those who have a more complex object and want to keep their code, u can also use #Query for fetching data.
u just need to do this like this:
#Repository
public interface VehicleRepo extends JpaRepository<Vehicle, String> {
#Query("from Vehicle v where v.type = :type and v.fkFranchise.zipCode = :zipCode")
List<Vehicle> findAllByTypeAndZipCode(String type, String zipCode);
}

Spring Data JPA Repository Method Query Cannot Parse Property Name Following OrderBy

My Repository Method Query cannot parse a property name that comes after the OrderBy, but it can if it follows the findBy or findAllBy. The attribute in my entity that is giving me issues is zIndex
Entity Class
#Entity
public class DisplayLayer
{
#Id
#Column(name="DISPLAY_LAYER_ID")
private Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="DISPLAY_CONTAINER_ID")
private DisplayContainer displayContainer;
#Column(name="NAME")
private String name;
#Column(name="Z_INDEX")
private Long zIndex;
#Column(name="DESCRIPTION")
private String description;
// Getters & Setters
}
Repository Class
public interface DisplayLayerRepository extends BaseRepository<DisplayLayer, Long>
{
// This one method query works just fine
public List<DisplayLayer> findByZIndex(Long pZIndex);
// These two throw the same error:
// Unable to locate Attribute with the the given name [ZIndex]
//
// public List<DisplayLayer> findAllByOrderByZIndexAsc();
// public List<DisplayLayer> findByDisplayContainerIdOrderByZIndexAsc(Long pDisplayLayerId);
}
So in my first method query, when OrderBy is not used, it correctly parses it as [zIndex], but when it follows the OrderBy for some reason it capitalizes the z: [ZIndex].
Is this a known issue, or am I doing something wrong?
EDIT
What makes me think there might be a bug with the parser is that if I update zIndex to IndexZ in my entity and then change my query methods from OrderByZIndex to OrderByIndexZ everything works.
This solution is not ideal though as the database table is Z_INDEX and that has a specific meaning when talking about layering of graphics.
Yes there is a bug but there is a simple workaround, please try :
displayLayerRepository.findAll(Sort.by(Sort.Order.desc("zIndex").ignoreCase()));
I suppose DisplayLayerRepository extends JpaRepository.
It's similar when you use parameters in your findBy method. Define in your repository empty method :
public List<DisplayLayer> findByDisplayContainerId(Long pDisplayLayerId, Sort sort);
Then you can call it by :
displayLayerRepository.findByDisplayContainerId(1L, Sort.by(Sort.Order.desc("zIndex").ignoreCase()));
You can use JpaSort in query. As in your case, it looks something like this:
Sort sort = JpaSort.unsafe(Sort.Direction.ASC, "zIndex");
List<DisplayLayer> zIndexes = displayLayerRepository.findByZIndex(pZIndex, sort);
and your query in Repository will look like this:
public List<DisplayLayer> findByZIndex(Long pZIndex, Sort sort);

How to Define Dynamic Model in Spring Framework

I am using Spring Framework as my back end
I have define know as Entity class The Entity class know contain 5 Fields
Below is the class , The code below dose not have setter getter part to make shorter and cleaner
#Entity
#Table(name="TblKnow")
public class Know {
#Id
private Double idKnow;
private String SubjectKnow;
private String BodyKnow;
private String ImgKnow;
private double CountView;
In JpaRepository interface i want to only query two column not all of columns.
public interface KnowRepository extends JpaRepository<Know,Double> {
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
Problem: i try to run but i get below exception
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [java.lang.Long]
But if i use without below query it is fine
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
You can create a custom constructor and use that to select only some fields in JPA query.
public Know(Double idKnow, String SubjectKnow) {
this.idKnow = idKnow;
this.SubjectKnow = SubjectKnow;
}
And the use this constructor in JPA query. Make sure you use complete path of class with package.
#Query("SELECT NEW packagePath.Know(idKnow,SubjectKnow) FROM Know")
query :
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
works dut to you select Know objects with fields that are mapped correct into Know class (and after wrapped into Page).
with query :
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
returns some custome bean/object that spring data can't map in correct way into Know class (as you declared it as expected return class wrapped into Page). add counstructor into Know with idKnow,SubjectKnow fields , or you can wrap it into some DTO with idKnow,SubjectKnow fields.

How to use projection interfaces with pagination in Spring Data JPA?

I'm trying to get a page of a partial entity (NetworkSimple) using the new feature of spring data, projections
I've checked the documentation and if I request only:
Collection<NetworkSimple> findAllProjectedBy();
It works, but if I'm using pageable:
Page<NetworkSimple> findAllProjectedBy(Pageable pageable);
It throws an error:
org.hibernate.jpa.criteria.expression.function.AggregationFunction$COUNT cannot be cast to org.hibernate.jpa.criteria.expression.CompoundSelectionImpl
Any one has already work with this ?
My NetworkSimple class is the following:
public interface NetworkSimple {
Long getId();
String getNetworkName();
Boolean getIsActive();
}
Note: This feature should work in the way described by the original poster but due to this bug it didn't. The bug has been fixed for the Hopper SR2 release, if you're stuck on an earlier version then the workaround below will work.
It is possible to use Pageable with the new query projection features introduced in Spring Data JPA 1.10 (Hopper). You will need to use the #Query annotation and manually write a query for the fields you require, they must also be aliased using AS to allow Spring Data to figure out how to project the results. There is a good example in spring-boot-samples part of the spring boot repository.
In your example it would be quite simple:
#Query("SELECT n.id AS id, n.name AS networkName, n.active AS isActive FROM Network n")
Page<NetworkSimple> findAllProjectedBy(Pageable pageable);
I have made the assumption that your entity looks something like this:
#Entity
public class Network
{
#Id
#GeneratedValue
private Long id;
#Column
private String name;
#Column
private boolean active;
...
}
Spring Data will derive a count query automatically for the paging information. It is also possible to make use of joins in the query to fetch associations and then summarise them in the projection.
I think you need create findAllProjectedBy() as specification.Then you can use findAll() method like this.
example :findAll(findAllProjectedBy(),pageable)
Following link may be help to find how to create specification in spring.
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
The issue may come from the method name. The by keyword means that you ae filterig data by a specific property: findByName for example. Its called query creation from method name:
http://docs.spring.io/spring-data/jpa/docs/1.10.1.RELEASE/reference/html/#repositories.query-methods.query-creation
So try with Page<NetworkSimple> findAll(Pageable pageable);
Even with spring-data-jpa 1.11.4, something like
public interface NetworkRepository extends JpaRepository<Network, String> {
Page<NetworkSimple> findAll(Pageable pageable);
}
would not compile; reporting
findAll(org.springframework.data.domain.Pageable) in NetworkRepository clashes with findAll(org.springframework.data.domain.Pageable) in org.springframework.data.repository.PagingAndSortingRepository
return type org.springframework.data.domain.Page<NetworkSimple> is not compatible with org.springframework.data.domain.Page<Network>
The workaround we found was to rename findAll to findAllBy, e.g.
public interface NetworkRepository extends JpaRepository<Network, String> {
Page<NetworkSimple> findAllBy(Pageable pageable);
}
You can use interface projection with Pageable like this :
Page<NetworkSimple> findPagedProjectedBy(Pageable pageable);
with some parameter :
Page<NetworkSimple> findPagedProjectedByName(String name, Pageable pageable);
Implementing interface projection with pagination
1. Our ResourceEntity.java class
#Getter
#Setter
#NoArgsConstructor
#Entity
public class ResourceEntity{
private Long id;
private String name;
}
2. Creating projection Interface name ProjectedResource.java, which maps data collected by the SQL query from repository layer method
public interface ProjectedResource {
Long getId();
String getName();
String getAnotherProperty();
}
3. Creating Repository layer method: getProjectedResources()
We are considering the database table name is resource.
We are only fetching id and name here.
#Query(name="select id, name, anotherProperty from resource", countQuery="select count(*) from resource", nativeQuery=true)
Page<ProjectedResource> getProjectedResources(Pageable page);
Hope the issue will be resolved!
You can use:
#Query("SELECT n FROM Network n")
Page<? extends NetworkSimple> findAllProjectedBy(Pageable pageable);

Resources