I'm using JPA repository for some toy project, I want to get List of object SOMETHING, but result is could not extract ResultSet; SQL[n/a].
This is my object (nothing is important, just focus on lob plz)
{
...
private Long id
#Lob
#Column(columnDefinition = "text")
private String content;
...
}
Then, I use repository to findByContentLike("CONTENT"), then result is failed, the reason is that cannot extract result.
why this happened? even i set on application.properties like spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
there anyone know about this error? please bring me to the light.
If you need auto parameter bound wrapped in %(wildcard) use
findByContentContaining("Content")
Or you need to manually add %(wildcard) in the string
findByContentLike("%Content%")
JPA-methodqueries require a special syntax. Most commonly they are build up as: findBy + a field of your entity. In your case, the like is redundant.
See this reference to the docs for examples.
As complexity increases, you might want to write your own queries, using JPQL. A small example:
#Query("SELECT p FROM Product p "
+ "LEFT JOIN p.categories category "
+ "WHERE UPPER(p.name) LIKE UPPER(CONCAT('%', COALESCE(:searchRequest, ''), '%')) "
+ "AND UPPER(p.description) LIKE UPPER(CONCAT('%', COALESCE(:description, ''), '%')) "
+ "AND p.price BETWEEN :priceLow AND :priceHigh "
+ "AND p.averageRating >= :averageRating "
+ "AND p.archived = :archived "
+ "AND ((category.name IN :selectedCategories) "
+ "OR (:amountOfSelectedCategories = 0 AND category IN (SELECT c FROM Category c))) "
+ "GROUP BY p "
+ "HAVING SIZE(p.categories) >= :amountOfSelectedCategories"
)
Page<Product> findAllBySearchModel(
Pageable pageable,
#Param("searchRequest") String searchRequest,
#Param("description") String description,
#Param("priceLow") BigDecimal priceLow,
#Param("priceHigh") BigDecimal priceHigh,
#Param("averageRating") double averageRating,
#Param("archived") boolean archived,
#Param("selectedCategories") List<String> selectedCategories,
#Param("amountOfSelectedCategories") int amountOfSelectedCategories
);
Don't forget to mark your entity class with #Entity and to have your repository extend JpaRepository<MyEntityClass, Long> where the Long corresponds with your entity's #Id field.
Related
I am new to Hibernate.My senior used 'findAll' method of JpaSpecificationExecutorWithProjection (interface) which is returning result based on a 'LIKE' operator but I required result based on 'AND' operator. Please guide me how I can solve this?.
Below is the part of code which displays it is hitting query based on 'LIKE' operator
where
(
upper(course0_.course_subject) like ?
)
and (
upper(course0_.course_sub_category) like ?
)
and course0_.course_status=?
and (
upper(course0_.course_exam_segment) like ?
)
and (
upper(course0_.course_category) like ?
)
It is using AND operator. The LIKE is for evaluating your individual params.
If you don't like the JPA-methodqueries, you can always write your own in your repository. Below is a quick example incorporating a left join and returning a Page-object. Please take a look here for some basic JPQL
#Query("SELECT p FROM Product p "
+ "LEFT JOIN p.categories category "
+ "WHERE UPPER(p.name) LIKE UPPER(CONCAT('%', COALESCE(:searchRequest, ''), '%')) "
+ "AND UPPER(p.description) LIKE UPPER(CONCAT('%', COALESCE(:description, ''), '%')) "
+ "AND p.price BETWEEN :priceLow AND :priceHigh "
+ "AND p.averageRating >= :averageRating "
+ "AND p.archived = :archived "
+ "AND ((category.name IN :selectedCategories) "
+ "OR (:amountOfSelectedCategories = 0 AND category IN (SELECT c FROM Category c))) "
+ "GROUP BY p "
+ "HAVING SIZE(p.categories) >= :amountOfSelectedCategories"
)
Page<Product> findAllBySearchModel(
Pageable pageable,
#Param("searchRequest") String searchRequest,
#Param("description") String description,
#Param("priceLow") BigDecimal priceLow,
#Param("priceHigh") BigDecimal priceHigh,
#Param("averageRating") double averageRating,
#Param("archived") boolean archived,
#Param("selectedCategories") List<String> selectedCategories,
#Param("amountOfSelectedCategories") int amountOfSelectedCategories
);
I want to filter out data from a database with few criteria (let's assume it is 8).
And below query method do this in a good way. But in fact, this criterias passed to the query method can be null (it means that should not be included to select query).
How I should handle this situation?
I really don't want to make n-methods to handle each case - it is not a good way.
#Query("SELECT NEW api.model.GeneralAnnouncementInfo(" +
"an.id, an.title, po.price, SUBSTRING(an.description, 1, 100), an.provider, an.creationDate, an.url, l.lessorType, concat(loc.city, ' ', loc.district)) " +
"FROM Announcement as an " +
"LEFT JOIN an.priceOffer as po " +
"LEFT JOIN an.lessor as l " +
"LEFT JOIN an.location as loc " +
"LEFT JOIN an.propertyData as pd " +
"WHERE l.lessorType = (:lessor) " +
"AND pd.roomNumber = (:rooms) " +
"AND pd.bathroomNumber = (:baths) " +
"AND pd.parkingAvailability = (:parking) " +
"AND pd.isSmokingAllowed = (:smokers) " +
"AND pd.isPetFriendly = (:pets) " +
"AND pd.area = (:realPrice) " +
"AND po.price = (:area) ")
Page<GeneralAnnouncementInfo> getAnnouncementsBySearchCriteria(Pageable pageable,
String lessor,
String rooms,
String baths,
String parking,
String smokers,
String pets,
String realPrice,
String area
);
I would recommend switching to the JPA Criteria API. It will give you the extra flexibility you are seeking (and which JPQL seems to be maxing out for your case). You can build your queries programmatically without any limitations and the best thing is that they get compiled; which means that no typos will survive (which are a nightmare to track in JPQL queries). Additionally you may want to use JPA metamodel classes; which add more robustness to your queries. At the end, your repository method would look something like this:
private EntityManager em;
private Page<GeneralAnnouncementInfo> getAnnouncementsBySearchCriteria(QueryParameters qParams) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SampleEntity> criteria = cb.createQuery(GeneralAnnouncementInfo.class);
Root<GeneralAnnouncementInfo> root = criteria.from(GeneralAnnouncementInfo.class);
// Programmatically build query details (conditions, joins, aggregations, translation, etc)
// ...
// ...
// ...
return em.createQuery(criteria).getResultList();
}
So my problem is the following:
I have a table I want a filter to apply to. This filter should call a query which finds based on the given information the reports.
This is how my query looks:
#Query("SELECT r FROM Report r WHERE r.importanceLevel = COALESCE(importance,'%')" +
"AND r.source = COALESCE(source,'%')" +
"AND r.resolvedStatus = COALESCE(resolvedStatus,'%')" +
"AND r.header LIKE + '%' COALESCE(query,'%') + '%'")
List<Report> getReportsByAppliedFilter(#Param("importance") int importance, #Param("source") String source,
#Param("resolvedStatus") int resolvedStatus, #Param("query") String query);
Problem is: IntelliJ does not like the following:
LIKE + '%' COALESCE(query,'%') + '%'
Error: expected, got +
Do you have any idea how to solve this otherwise?
Yeah, time to go to bed. You dont use + for concat , you use concat():
#Query(value = "SELECT r FROM Report r WHERE r.importanceLevel = COALESCE(importance,'%')" +
"AND r.source = COALESCE(source,'%')" +
"AND r.resolvedStatus = COALESCE(resolvedStatus,'%')" +
"AND r.header LIKE CONCAT('%', COALESCE(query,'%'), '%')")
If your column name is request_status and table name is connections then use COALESCE like
#Query(value = "SELECT connections.id, COALESCE(connections.request_status,'') as request_status.... ", nativeQuery = true)
List<ZXYType> xysfunction();
Here if request_status is null then it will be replaced by an empty string.
I have following native query method in my repository:
#Query(value="SELECT appSub.ApplicationFormId as appFormId, appSub.profileId as profileId, "
+ "p.CASId as profileCASId, ps.programId as programId FROM [unicas_config].[dbo].ApplicationFormEarlyDecisionConfig appFormED "
+ "INNER JOIN [unicas_ux].[dbo].ApplicationSubmission appSub ON appFormED.ApplicationFormId = appSub.applicationFormId "
+ "INNER JOIN [unicas_ux].[dbo].Profile p ON appSub.profileId = p.id "
+ "INNER JOIN [unicas_ux].[dbo].ProgramSelected ps ON p.id=ps.ProfileId AND appSub.applicationFormId = ps.instanceId "
+ "WHERE appFormED.EarlyDecisionVerdictDate >=:fromDate AND appFormED.EarlyDecisionVerdictDate <:toDate "
+ "AND appSub.EarlyDecisionStatus='Applied Early Decision' "
+ "AND appSub.ApplicationStatus='Received' "
+ "AND ps.IsPaid =1 "
+ "ORDER BY appSub.ApplicationFormId",nativeQuery = true)
List<Object[]> getAllEarlyDecisionApplicantsWithPaidProgramsOnVerdictDate(#Param("fromDate") Date fromDate, #Param("toDate") Date toDate);
Now, I want to map the returned result:
long appFormId = (Long)obj[0]
long profileId = (Long)obj[1]
long programId = (Long)obj[3]
When I am doing that, I am getting java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long as Hibernate consider these ids of Integer type instead of Long.
Please, tell me how could I programatically tell Hibernate to return proper type.
To be on the safe side, I always cast numeric types to Number and then get the value of desired type from it, as JDBC driver can return Integer, Long, BigDecimal, etc. depending on the type of the database column:
((Number) obj[0]).longValue()
Of course, don't forget to check for null if column is nullable.
#My doubt is the partId in Product table can be null ,so if the partId is null I’m not able to see the product. If my Product Table has 11 entries and 2 entries have partId as null , Iam able to see only 9 entries
String hql = "from " + Product.class.getName() + " bs, "
+ Part.class.getName() + " dm, "
+ Manufacturer.class.getName() + " m where "
+ " m.id = bs.manufacturerId and dm.id = bs.partId ";
========================================
The ouput has to be like this
productName | PartName | Manufactuer Name
You need to do left joins instead of inner joins. But this is only possible if your entities are associated together instead of containing each other's IDs.
As is, it's plain impossible with HQL.
Given your query, you probably should have a ManyToOne between Product and Manufacturer, and a ManyToOne between Product and Part.
Also, your query would be much more readable if you didn't concatenate class names and if you used proper alias names:
String hql = "from Product product, Part part, Manufacturer manufacturer"
+ " where manufacturer.id = product.manufacturerId"
+ " and part.id = product.partId";
Once the associations exist, the query should just be
String hql = "select product.name, part.name, manufacturer.name"
+ " from Product product"
+ " left join product.part part"
+ " left join product.manufacturer manufacturer";