I implemented a method that allows me to generate a test ( entire of question ) automatically but the problem is :
the method will obviously take the number of random questions but also the category of questions generated (I have a entiƩ category and therefore a table too) I don't know where i will put the category in query.
and secondly RANDOM() is not taked by JPQL what can i do ?
schema of the DataBase
public List<Question> prepareRandomTest(int number_of_questions, Categorie categorie){
String jpql = "SELECT q FROM Question q ORDER BY RANDOM() LIMIT "+number_of_questions ;
Query query = entityManager.createQuery(jpql);
return query.getResultList();
}
You are trying to use Java Persistence Query Language here, Hence your solution is not taking RANDOM into account. Use Native query and build Query from native sql string, Native query is just a plain sql statement without Entity object reference (like Question). This way a normal sql keywords like RANDOM etc are easily read.
Native Query Tutorial
Instead of Using
String jpql = "SELECT q FROM Question q ORDER BY RANDOM() LIMIT "+number_of_questions ;
use:
"SELECT * FROM question where category="+category+" ORDER BY RANDOM() LIMIT "+number_of_questions;
Additional Advice:
Get the category string from an "Enum" in your code to match the string value in the database category column.
Related
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.
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.
I have a custom query along these lines. I get the list of orderIds from outside. I have the entire order object list with me, so I can change the query in any way, if needed.
#Query("SELECT p FROM Person p INNER JOIN p.orders o WHERE o.orderId in :orderIds)")
public List<Person> findByOrderIds(#Param("orderIds") List<String> orderIds);
This query works fine, but sometimes it may have anywhere between 50-1000 entries in the orderIds list sent from outside function. So it becomes very slow, taking as much as 5-6 seconds which is not fast enough. My question is, is there a better, faster way to do this? When I googled, and on this site, I see we can use ANY, EXISTS: Postgresql: alternative to WHERE IN respective WHERE NOT IN or create a temporary table: https://dba.stackexchange.com/questions/12607/ways-to-speed-up-in-queries-under-postgresql or join this to VALUES clause: Alternative when IN clause is inputed A LOT of values (postgreSQL). All these answers are tailored towards direct SQL calls, nothing based on JPA. ANY keyword is not supported by spring-data. Not sure about creating temporary tables in custom queries. I think I can do it with native queries, but have not tried it. I am using spring-data + OpenJPA + PostgresSQL.
Can you please suggest a solution or give pointers? I apologize if I missed anything.
thanks,
Alice
You can use WHERE EXISTS instead of IN Clause in a native SQL Query as well as in HQL in JPA which results in a lot of performance benefits. Please see sample below
Sample JPA Query:
SELECT emp FROM Employee emp JOIN emp.projects p where NOT EXISTS (SELECT project from Project project where p = project AND project.status <> 'Active')
Calling .ToString() to a IQueryable will return the generated SQL query with the values of the variables not plugged in yet. So there are these p__linq__n with n=0, 1, 2... in the query itself.
eg: SELECT * FROM foo WHERE x = p__linq__0
Question: Is it possible to get the final query? with the values of these variables already plugged into the query?
eg: SELECT * FROM foo WHERE x = 6
EF parametrizes queries to avoid Sql injections attacks and to be able to cache and re-use the same query even if some values change. To see parameters you can use the logging feature introduced in EF6. See this blogpost series for more details.
This is my simple JPQL:
SELECT s
FROM Site s
GROUP BY s.siteType
siteResult = q.getResultList();
for (Site site : siteResult) {
// loops all sites
}
This query returns all sites, including sites of the same siteType.
I'm using JPA 2.0 Eclipselink.
Whats wrong here?
Such a query does not make sense. If you use GROUP BY, other attributes in SELECT should be aggregated. As it is said in JPA specification:
The requirements for the SELECT clause when GROUP BY is used follow
those of SQL: namely, any item that appears in the SELECT clause
(other than as an aggregate function or as an argument to an aggregate
function) must also appear in the GROUP BY clause. In forming the
groups, null values are treated as the same for grouping purposes.
If you think SQL counterpart of your query:
SELECT s.attr1, attr2, s.siteType
FROM site s
GROUP BY (s.siteType)
you notice that it is hard to imagine which possible value of attr1 and attr2 should be chosen.
In such a case EclipseLink with derby just drops GROUP BY away from the query, which is of course little bit questionable way to handle invalid JPQL. I like more how Hibernate+MySQL behaves with such a invalid JPQL, it fails with quite clear error message:
java.sql.SQLSyntaxErrorException: The SELECT list of a grouped query
contains at least one invalid expression. If a SELECT list has a GROUP
BY, the list may only contain valid grouping expressions and valid
aggregate expressions.
Answer to comment:
One Site contains probably also attributes other than siteType as well. Lets use following example:
public class Site {
int id;
String siteType;
}
and two instances: (id=1, siteType="same"), (id=2, siteType="same"). Now when type of select is Site itself (or all attributes of it) and you make group by by siteType, it is impossible to define should result have one with id value 1 or 2. Thats why you have to use some aggregate function (like AVG, which gives you average of attribute values) for remaining attributes (id in our case).
Behind this link: ObjectDB GROUP BY you can find some examples with GROUP BY and aggregates.