Spring Data: Getting NonUniqueResult Problem for the query - postgresql

Hello experts of the world. Need some help concerning executing a query with SpringData.
The expectation is to execute the Query below in the Spring Data annotation by combining with the repository method name (Automated Query Construction) to get a unique result. Apparently it fails from time to time by saying the result is not Unique.
The question here is if the method name is still considered in Query Construction while also executing the query in the annotation.
#Query("SELECT r from Revision r WHERE r.revisionBid = ?1 AND r.revisionStatusId = ?2 ORDER BY r.lastModifiedDate DESC")
Optional<Revision> findFirst(Integer revisionBid, Integer revisionStatusId);
Thanks in advance!
The query creation for limiting to 1 result is defined here with FIRST & TOP included in the method name.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation

I don't think "findFirst" will work when you're using an #Query, as the query will be constructed from HQL expression in the #Query rather than the fluent API passing over the method name. Because of this, when the query returns multiple results, it will throw the exception as the Optional is told to wrap a single returned object, not a collection. Add a LIMIT clause to the HQL query and you should be good.

Related

Query annotation not working for max(id)

I have a domain object GenJournal and it has an "id" member (Long) that's auto-generated. I also have a JPA repository that I've added ...
#Query("select coalesce(max(u.id), 0) from GenJournal u")
Long getMaxId();
The method getMaxId() returns zero or null before I added coalesce. I have two rows in my database with ids 1 and 2. Can anyone help me determine why this doesn't work?
I'm trying to get the latest or max id so that I can use the find method after to return the most recent GenJournal object in my service class.
I'm stumped and really need some options or strategy to determine why this doesn't work.
You could use "Native Query" feature by passing nativeQuery = true param into #Query annotation like this
#Query("select coalesce(max(u.id), 0) from Gen_Journal_Table u", NativeQuery = true)
Long getMaxId();
My issue was two-fold. First I was getting null without the use of "coalesce". That caused me to think that this didn't work. When I adopted the use of "coalesce" I didn't realize that my table had no records and was returning the zero (0). My table in the production profile did have two records and I was expecting an id of 2.
I was manually checking the wrong database and setting expectations that were incorrect.

Spring Data - JPA Repository - Too many parameters in a Query

I'm working with Spring Data Repositories manipulating data from a PostreSQL database.
In one of my repositories, I have a very simple query:
#Query(value = "FROM MyEntity entity WHERE entity.entityId IN (:entityIds)")
Collection<MyEntity> getEntitiesByIds(#Param("entityIds") Collection<Long> entityIds);
The problem is, when I pass in a collection that has more than 32k~ ids this query throws the following error:
java.io.IOException: Tried to send an out-of-range integer as a 2-byte value: 70324
I did some research and found out that this error happens because postgresql jdbc driver has a limit of 32k~ parameters you can pass in to a query. So I have two options here:
Do the query in batches. At this point I think this is my best shot but I was hoping to find a solution so I can pull my rows in one database call.
Build a temporary table with the ids, then join it against MyEntity table, but I'm running again into the same original problem. For this approach I was thinking to pass a String with all the concatenated ids and then use a native query to pull the information but it its not working as I expected:
#Query(value = ";WITH cteAllEntityIds(entity_id) AS( " +
"VALUES (?1)) " +
"SELECT p.* FROM my_entity e " +
"JOIN cteAllEntityIds cte ON e.entity_id = cte.entity_id", nativeQuery = true)
Collection<ProfileViewEntity> getProfilesByIds(String profileIds);
Of course, the parameter I'm passing in is a String whereas the entity_id is a number in the data base.
Do you know a way to accomplish approach #2? How to build queries dynamically and make jpa to interpret it that way?
Do you know a better solution to this problem?
Any suggestions are welcome.
Thanks.

OrientDB indexes are not working properly with formatted params used in server functions

OrientDB is throwing a java.lang.ClassCastException when a sever function (a query on indexed fields) is executed with formatted params.
Following messages are seen with the exception.
"Error on using index", "Probably you need to rebuild indexes. Now executing query using cluster scan
e.g.
db.query("SELECT FROM Employee WHERE department = ?", departmentRid);
where, Employee.department is indexed with NOT_UNIQUE_HASH_INDEX
When I removed the formatted params and injected them manually index worked out fine.
e.g.
db.query("SELECT FROM Employee WHERE department = " + departmentRid);
Any reason why the first approach didn't work? I'd like to refrain from injecting the params manually.
Note that the both approaches gives me the correct result. The problem is that the index is not applied for the first approach.
I am using orientdb-community-2.1.0
Appreciate your help.
I tried it with version 2.1.0, I have the NOTUNIQUE_HASH_INDEX on department field of Employee and it works

Spring CRUD repository: is there findOneByMaxXYZColumn()?

My requirement:
fetch ONE object (e.g RetainInfo ) from table RETAIN_INFO if VERSION column has max value
Does CRUD repository support for an interface method like
findOneByMaxRetVersionAndCountry("DEFAULT")
Equivalent db2 sql:
select RET_ID, max(ri.RET_VERSION) from RETAIN_INFO ri where ri. COUNTRY='DEFAULT' group by RET_ID fetch first 1 rows only;
This query selects an ID, but I would actually want the RetainInfo object corresponding the SINGLE row returned by the query.
I prefer to get that without using custom query, i.e using findBy or some other method/interface supported by Spring CRUD.
You could use limiting in combination with sorting (spring data reference:limit query results). Declare a method similar to the following in your CrudRepository interface :
RetainInfo findTopByCountryOrderByRetVersionDesc(String country);
You can also use findFirst to get the first result. Before getting the result, make sure to use Orderby and then the ascending(Asc) or descending(Desc). As an example if you want to order by version and retrieve based on productName
RetainInfo findFirstByProductNameOrderByVersionDesc(String productName);
Spring Data doesn't provide an expression to select a max value. All supported query parts could be found in the Spring 1.2.0.RELEASE docs: Appendix A. Namespace reference or line 182 of org.springframework.data.repository.query.parser.Part.
Also feel free to create a feature request at Spring's Jira page.

JPQL - Predicate and criteriaAPI

I'd like to write a Predicate which is calculated based on 2 columns.
for example - I have a daysBetween (int) and lastSent (date).
I'd like to know if there's a possibility to perform the following query :
select from X where the last_sent + [some other column which is interval] lessThan now()
something similar to (and I now this is not the correct way to write it..),
builder.between(userData.<Date>get("lastSent").addDays(userIntervals.<Integer>get("interval")),DateUtils.now());
Is there anyway of writing such a query using predicates?
JPA Criteria does not define an addDays() API. You can call a database specific function through the function() API,
See,
http://en.wikibooks.org/wiki/Java_Persistence/Criteria#Special_Operations
Some JPA providers provide extensions to JPQL and Criteria.
See,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Criteria#JpaCriteriaBuilder_and_EclipseLink_Extensions
and,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#EclipseLink_Extensions_.28EQL.29