playframework selecting from h2 database - jpa

I am trying downloading all records from table in h2 buildin database in playframework.
I am facing an error:
[IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: * near line 1, column 8 [SELECT * FROM TABLE]]
Method CODE i class Table:
#Transactional(readOnly=true)
public static Result view() {
Query query = JPA.em().createQuery("SELECT * FROM TABLE");
List<Table> downloaded_from_db = query.getResultList();
System.out.println(downloaded_from_db.getClass());
return ok(view.render("none"));
}
Please help me. I would like to see downloaded records in console in simple view.
Please give me some tips or good tutorial.
After changing my class loooks like this:
#Transactional(readOnly=true)
public static Result view() {
List<MedicalIncidents> data = JPA.em()
.createNativeQuery("SELECT * FROM MedicalIncident")
//.createQuery("Select m from MedicalIncident m")
.getResultList();
System.out.println(data);
AND I think it works, cause I have 2 entries in that table in database:
But System.out.println(data) return in plaay console:
[[Ljava.lang.Object;#70a0c9be, [Ljava.lang.Object;#4c1d12b6]
But it should return this object by model name like in example: computer-database-jpa:
[models.Computer#214c6fde, models.Computer#63728eb3, models.Computer#75f6bcc6, models.Computer#19e3a7ab, models.Computer#3114d8d4, models.Computer#4fa75f78, models.Computer#756ce822, models.Computer#40fc4c68, models.Computer#73fc612c, models.Computer#3e4fcb31]
So I think that there is something wrong with it. Please help

You mxied SQL queries with JPQL query. The method you used createQuery needs an JPQL query:
SELECT e FROM Entity e
Also please note in JPQL there is no SELECT *. If you want to write a SQL query, use the method em.createNtiveQuery().

Related

Using JPA to call native Postgresql command

I am using a third party library to perform mass inserts into a database PgBulkInsert . It takes inserts that would normally take 30 minutes and performs them in 30 seconds. We have noticed that overtime there is disk usage leakage, but we figure out that performing a table reindex appears to corrcect the issue. I am trying to use my JPA Entity Manager to perform a native update. The below code works but contains potential SQL injection vulnerability.
#Stateless
public class ReindexService {
#PersistenceContext(unitName = "my-ds")
private EntityManager em;
public void reindexTable(String table) {
String queryStr = "REINDEX TABLE " + table;
Query query = em.createNativeQuery(queryStr);
query.executeUpdate();
}
}
When I pass in string "alert" to index the alert table it yields the following SQL output
/* dynamic native SQL query */ REINDEX TABLE alert
When I attempt to use a positional parameter it yields a SQL error
String queryStr = "REINDEX TABLE ?";
Query query = em.createNativeQuery(queryStr);
query.setParameter(1, table);
query.executeUpdate();
This yields the following error output
/* dynamic native SQL query */ REINDEX TABLE ?
SQL Error: 0, SQLState: 42601
ERROR: syntax error at or near "$1"
Position: 46
I get a similar error when I try to use a name parameter
String queryStr = "REINDEX TABLE :table";
Query query = em.createNativeQuery(queryStr);
query.setParameter("table", table);
query.executeUpdate();
This yields the same error
/* dynamic native SQL query */ REINDEX TABLE ?
SQL Error: 0, SQLState: 42601
ERROR: syntax error at or near "$1"
Position: 46
Does anyone know how I can call a the native Postgresql reindex table command using my entity manager in a manner without adding a SQL injection vulnerability? I am using Hibernate 5.3.6.Final but would prefer a non-implementation specific solution.
I also tried to access the Connection and perform a JDBC call and it seems to give the error
final Session session = //get session from entity manager
session.doWork(conn -> {
try (PreparedStatement stmt = conn.prepareCall(REINDEX TABLE ?)) {
stmt.setString(1, table);
stmt.execute();
}
});
Yields the same errors as above
SQL Error: 0, SQLState: 42601
ERROR: syntax error at or near "$1"
Position: 15
Identifiers can't be passed as parameters. If you don't expect the table name to come from user input (it sounds a bit strange), you may try using an enumeration of all the tables which you want to reindex, and pass enumeration values to your service (and just concatenate strings).
If you do expect table names to come from untrusted sources, you can try enclosing identifier with double-quotes and escaping existing double-quotes.
There is also a function quote_ident in PostgreSQL which can be used to quote identifiers properly. So you can create a stored procedure which takes a regular argument from your JPA code and uses quote_ident and EXECUTE a constructed query
.
Our workaround was to create a Database Function and call it using a native query
The database function
CREATE OR REPLACE FUNCTION reindex_table(table_in text)
RETURNS void
SECURITY DEFINER
AS $$
BEGIN
EXECUTE FORMAT('REINDEX (VERBOSE) TABLE %I', table_in);
RETURN;
END;
$$ LANGUAGE plpgsql;
Here is the Service code for calling the function
public void reindexTable(String table) {
String queryStr = "select reindex_table(?)";
final Session session = //obtain Hibernate Session from Entitymanager
session.doWork(conn -> {
try (PreparedStatement stmt = conn.prepareCall(queryStr)) {
stmt.setString(1, table);
stmt.execute();
}
});
}
This is something weird ,But Just try, table is a reserved keyword in PostgreSQL. So try changing the variable name.
String queryStr = "REINDEX TABLE :tableName";
Query query = em.createNativeQuery(queryStr);
query.setParameter("tableName", "AUTH_IND");
query.executeUpdate();
From the Documentation :
"select" could be used to refer to a column or table named “select”, whereas an unquoted select would be taken as a key word and would therefore provoke a parse error when used where a table or column name is expected.
https://www.postgresql.org/docs/current/sql-syntax-lexical.html

Spring JPA repository casting error when using JPQL

I have a PagingAndSorting JPA repository declared. I am using the #Query annotation.
I am getting an exception when I call the get() method on an Optional object from the findById(id) method of the repository.
The weird thing is it only happens when I use JPQL.
The code works if my query is native:
#Override
public BatchDto findById(String id) {
Optional<Batch> findResult = this.batchRepository.findById(id);
if (!findResult.isPresent()) return null;
Batch entity = findResult.get(); **<-------- Cast Exception Here**
BatchDto dto = this.mapper.toDto(entity, BatchDto.class);
List<BatchTransaction> transactions = entity.getTransactions();
dto.setTransactionDtos(mapper.toListDto(transactions, TransactionDto.class));
return dto;
}
Inspecting the findResult object with a breakpoint - I can see:
Optional[net.domain.data.batch#4b8bb6f]
when I have nativeQuery = true in the #Query annotation.
#Query(value = Sql.FindBatchById, nativeQuery = true)
Here is the query being used:
SELECT DISTINCT(B.batchNumber), COUNT(B.batchNumber) as TransactionCount FROM BATCH B WHERE B.batchReferenceNumber = :id GROUP BY B.batchNumber
However if I change it to JPQL and remove the nativeQuery=true attribute - the findResult is
Optional[[Ljava.lang.Object;#76e04327].
and I get a ClassCastException:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to net.domain.data.batch
So bottom line - this works when specify nativeQuery=true and fails when I try to use JPQL.
I would prefer not to specify nativeQuery as we will eventually port this db to Oracle.
First of all the query shown below doesn't return a single Batch instance. Since there are distinct and count aggregate functions, the query will return a List of aggregates.
To be able to read that statistics you can add appropriate method into the batchRepository. Something like this:
#Query("SELECT DISTINCT(B.batchNumber) as dist, COUNT(B.batchNumber) as cnt FROM BATCH B GROUP BY B.batchNumber")
List<Map<Long, Long>> findStatistics();
and then iterate through the list.
UPD
If the id parameter exactly guarantee that will return a single record, you can change a return type to a Map
#Query("SELECT DISTINCT(B.batchNumber) as dist, COUNT(B.batchNumber) as cnt FROM BATCH B WHERE B.batchReferenceNumber = :id GROUP BY B.batchNumber")
Map<Long, Long> findStatisticsById(#Param("id") Long id);

Laravel 5.4 order by related table after using `with` statement

This is my simple structure:
public class Post{
public function user(){
return $this->belongsTo(User::class);
}
}
This is how I query (the query has pagination):
$query = Post::query();
$query->with('user');
I want to sort by user.name.
Now, I know that I can go $query->with('user',function(){...order by here});
But I need a detached method that I can run later in the stack.
$query->user->orderBy('name');
$query->user()->orderBy('name');
This https://stackoverflow.com/a/38741988/936651 says that it is possible, but I get the error: Undefined property/method: Illuminate\Database\Eloquent\Builder::$user
Is there any way to sort by related table after using with statement?
Thanks
Your code doesn't work because when you do $query = Post::query(); it will return an instance of the Query Builder, so when you after do $query->user() it gives you an error because the Query Builder does not have the method user(), that method exists in your Post model.
I won't provide any code since you've mentioned you already know how to do the with() way..

Cannot create TypedQuery for query with more than one return

I am using the following JPA query and i am getting the java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return Exception.
TypedQuery<RaBdrRating> uQuery =
(TypedQuery<RaBdrRating>)entityManager.createQuery("
SELECT r.activePackage,SUM(r.duration),SUM(r.charge),COUNT(r)
FROM RaBdrRating r WHERE r.callType = :callType
and r.startDate between :startDate and :endDate
GROUP BY r.activePackage",RaBdrRating.class);
uQuery.setParameter("callType", model.getCallType());
uQuery.setParameter("startDate",startDate);
uQuery.setParameter("endDate",endDate);
List<RaBdrRating> listOfPackages = uQuery.getResultList();
Can any one tell me what is wrong in my query.....I am new to JPA and i am not getting what is the problem and strucked up here.If any one have idea please tell me.
I go the same error:
Cannot create TypedQuery for query with more than one return using requested result type
Solution:
Having a Query like this:
Select e.fieldA, e.fieldB, e.fieldC From Entity e
You have to declare a constructor with the parameters specified on query:
package somepackage;
public class Entity {
...
public class Entity() {}
public class Entity(Type fieldA, Type fieldB, Type fieldC) {
this.fieldA = fieldA;
this.fieldB = fieldB;
this.fieldC = fieldC;
}
....
}
Finally, modify your query
Select NEW somepackage.Entity(e.fieldA, e.fieldB, e.fieldC) From Entity e
You are indicating how the objectes will be created.
This seems to be this bug: https://hibernate.onjira.com/browse/HHH-6304
It is apparently fixed in version 4.1.5.

How to call Named Query

I wrote a named query in the entity class Voter
NamedQuery(name = "Voter.findvoter", query = "SELECT count(*) FROM Voter v WHERE v.voterID = :voterID" and where v.password= : password),
I want to call this named query and I also need to set voterID and password.
Can you help me. Thank you
I assume you've missed the # symbol on your NamedQuery annotation?
In the code, you'd call it like this:
List results = em.createNamedQuery("Voter.findvoter")
.setParameter("voterID", "blah")
.setParameter("password","blahblahblah")
.getResultList();
There are two obvious issues with your named query that would cause a problems:
It is an annotation so it should be #NamedQuery not just NamedQuery
Your query is currently:
query = "SELECT count(*) FROM Voter v WHERE v.voterID = :voterID" and where v.password= : password.
The problem is that you terminate your String after :voterID, instead of after :password and you have "where" twice and you have a space between ":" and "password". Your query should look like this:
query = "SELECT count(*) FROM Voter v WHERE v.voterID = :voterID and v.password= :password"
(I have just moved the " to the end and removed the second "where" and the space after the ":")
The common steps are (named query or otherwise)
Create a query - em has five create methods.
Set the query up with parameters if needed - the query interface has these methods.
Execute the query - the query interface has 3 execution related methods.
with the above three steps you can run any JPA query.
Actually brent is right your NameQuery should be something like this,
#NamedQuery(name = "Voter.findvoter", query = "SELECT count(*) FROM Voter v WHERE v.voterID = :voterID AND where v.password = :password")
#Entity
public class Voter implements Serializable{ ... }
and somewhere else you should try this one (which Dick has already said)
public class VoterFasade{
public List<Voter> findVoter(long id,String password){
List<Voter> results = em.createNamedQuery("Voter.findvoter")
.setParameter("voterID", id)
.setParameter("password",password)
.getResultList();
return result;
}
}
then you could use it like
#Inject
VoterFasade voterFasade;
///
long id=12;
voterFasade.findVoter(id);
should actually working.(its an uncompiled code).
you could also do it with Repository, check the link below, part Repository Listing23.Example repository
enter link description here