I'm using #query annotation but when I try to fetch count of records it throws
java.sql.SQLException: Column 'allowPartialPay' not found.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1094) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:997) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:983) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:928) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1162) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:1781) ~[mysql-connector-java-5.1.31.jar:na]
I'm writing my custom queries in repository.
InvoiceRepository.java
public interface InvoiceRepository extends JpaRepository<Invoice, Integer>{
Invoice findByInvoiceNumber(String invoiceNumber);
List<Invoice> findByUserId(int id);
#Query(value = "select c.id,c.business_name,count(i.id) from client c join invoice i on c.id = i.client_id where i.date <= :agingDate group by c.id",nativeQuery=true)
List<Invoice> findInvoiceCount(#Param("agingDate")Date agingDate);
}
ReportService.java
if(report.getReportBy().equals("invoiceCount")){
result = invoiceRepository.findInvoiceCount(report.getAgingDate());
}
Invoice.java
#Entity
#Table
public class Invoice {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private int id;
#ManyToOne
private Client client;
#Column
private boolean allowPartialPay;
}
Database
It comes during mapping result set into java Invoice class (as you declared it as return type List for method findInvoiceCount() ). native query return in your case Object[] instead of List.
You can see it in log exception
ResultSetImpl.findColumn(ResultSetImpl.java:1162
So it happens in result mapping stage ,after query has executed.
#Query(value = "select c.id,c.business_name,count(i.id) from client
c join invoice i on c.id = i.client_id
where i.date <= :agingDate group by c.id",nativeQuery=true)
List<Invoice> findInvoiceCount(#Param("agingDate")Date agingDate);
spring data gets result set from query result and tries to map it into Invoice field by field (try to contruct Invoice class ). But actual type it's Object[].
If you need get some DTO as result your query , with fields like is result set : 'c.id,c.business_name,count(i.id)' use #SqlResultSetMapping (you can map result columns from select query into your dto). Or change return type from List to Object[] and iterate it as you need.
Here is example for Result Set Mapping: The Basics.
Related
Let's say I have a query like this:
Query object
public class myObject {
private String code;
private String name;
}
query method
#Query(nativeQuery = true,value = "...")
findByAcodeAndBname(List<MyObject> queryObject);
Pseudocode of the query
select a.code, b.name from tableA a
left join table b on a.column = b.column
where a.code = ${} b.name = ${}
Since it could cause performance issues just simply using foreach code in Java to do the query, how do I map every pair of a.code and b.name using native JPA query like mybatis foreach tag? Or is it posssible?
I think you don't need native query here, because the costs of querying data from the database and transfering it over network are higher than any related Java operations.
Instead of native query you can use JPQL query, e.g.
#Query("select new com.tsypanov.domain.HasIdAndNameDto(e.id, e.name)" +
" from ManyFieldsEntity e " +
"where e.name = :name")
List<HasIdAndName> findAllByNameUsingDto(#Param("name") String name);
Here we call constructor of DTO from JPQL query passing the fields from our entity. The DTO class must have the specified constructor:
#RequiredArgsConstructor
public class HasIdAndNameDto {
private final Long id;
private final String name;
}
I have an entity:
#Entity
#Table(name ="cats")
public class Cat {
#Id
#Column(name="name")
private String name;
#Column(name="age")
private int age;
#Column(name="color")
private String color;
#Column(name="weight")
private int weigth;
..
}
1. I need to delete it from database using EntityManager:
#Override
public void delete(Cat cat) {
entityManager.remove(cat);
}
Problem: I have a Map<String, Cat> which contains all this elements. I get it by name from map IllegalArgumentException -> "Removing a detached instance com.entities.Cat#cats".
Question: How can i do it without getting from database by key?
2. I need to getList with limit and offset.
To get all the elements i can just use:
entityManager.createNativeQuery("SELECT name, age, color, weight FROM cats");
Without entityManager i used prepatedStatement with:
"SELECT name, age, color, weight FROM cats LIMIT ?,?"
Question:
How can i do it using entityManager?
Do entityManager have something like preparedStatement?
With EntityManager you can use Query objects. It provides you with several different methods to build your queries, which you can see in the Docs.
From there, you can use a Query to perform a select or execute an update into the db.
Update example:
//:id is a parameter you can set
Query query = entityManager.createQuery("delete from Entity e where e.id = :id");
query = query.setParameter("id", id);
query.executeUpdate();
Select example (using TypedQuery which implements Query:
String sql = "select e from Entity e";
TypedQuery<Entity> query = entityManager.createQuery(sql, Entity.class);
System.out.println(query.getResultList());
You can determine limit and offset like this:
query = query.setFirstResult(offset);
query = query.setMaxResults(limit);
If you have an entity at hand you can (and should) delete it using your EntityManager with remove(). You're getting that error because your entity is detached - that is, your EntityManager isn't aware of its existence.
To "attach" entities to your manager you can use merge(). However, if said entity doesn't exist in the database it will be inserted, and if it exists but has different fields from your object it will be updated.
public void delete(Cat cat) {
if(!entityManager.contains(cat)) {
entityManager.merge(cat);
}
entityManager.remove(cat);
}
To insert entities for the first time you can also use persist(). For the differences between merge() and persist(), see this.
If you need to use EntityManager, then simply use reference:
entityManager.remove(entityManager.getReference(Cat.class, id));
This way the entity won't be fetched from db, but will be deleted.
Using query is also an option:
Query query = entityManager.createQuery("delete from Entity e where e = :entity");
query = query.setParameter("entity", entity);
query.executeUpdate();
You can create Query using EntityManager#createQuery. Then set parameters: firstResult and maxResults:
query.setFirstResult(10).setMaxResults(20);
This will take 20 entities starting from 10th.
Entity
#Builder
#Getter #Setter
#ToString(doNotUseGetters = true)
#EqualsAndHashCode(doNotUseGetters = true)
#Table(value = "entity")
public class Entity implements Serializable {
#PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
#CassandraType(type = DataType.Name.UUID)
private UUID Id;
#Column("list_name")
#CassandraType(type = DataType.Name.TEXT)
private String name;
#Column("type")
#CassandraType(type = DataType.Name.TINYINT)
private Byte type;
Entity Repo
#Repository
public interface EntityRepo extends BaseRepo<Entity, UUID> {
#Query("SELECT * FROM entity WHERE id IN (:id)")
Collection<ListEntity> findByIds(#Param("id") Collection<UUID> listIds);
#Query("SELECT * FROM entity WHERE list_id = :id")
ListEntity findById(#Param("id") UUID id);
}
Query
listRepo.findByListId(UUIDs.random())
listRepo.findByListIds(Arrays.asList(UUIDs.random())
Both results in
CassandraInvalidQueryException/InvalidQueryException
org.springframework.data.cassandra.CassandraInvalidQueryException: Query; CQL
[SELECT * FROM lists WHERE list_id IN (?)]; UUID should be 16 or 0 bytes (20);
nested exception is com.datastax.driver.core.exceptions.`InvalidQueryException: UUID should be 16 or 0 bytes (20)
Anything missing here? Can somebody help?
It looks like as if IN queries using UUID are not possible by passing in a collection into a single bind value.
Here's what happens:
Spring Data transforms your String-query
SELECT * FROM entity WHERE id IN (:id)
into Cassandra's notation using positional query arguments
SELECT * FROM entity WHERE id IN (?)
and binds the given parameter to ?. Let's transform this into an executable piece of code:
session.execute(new SimpleStatement("SELECT * FROM entity WHERE id IN (?)",
Arrays.asList(UUIDs.random())));
When you run this snipped, then you'll end up with InvalidQueryException again. We can still make an IN query happen, but we need to unfold parameters:
new SimpleStatement("SELECT * FROM entity WHERE id IN (?, ?)", UUIDs.random(), UUIDs.random())
In an ideal world, Cassandra could accept a List (or Set) of items to keep the query string agnostic against the actual number of arguments.
It is work at me.
Use: findAllBy[object-property]In where [object-property] is name of property of the MyModel UUID.
#Table("example")
public class MyModel {
#PrimaryKeyColumn(name = "uuid", type = PrimaryKeyType.PARTITIONED)
private UUID uuid;
#Column("...")
...
}
public interface MyRepository extends CassandraRepository<MyModel, UUID> {
List<Restaurant> findAllByUuidIn(Collection<UUID> uuidButIfYouWant);
}
// It is OK
return this.myRepository.findAllByUuidIn(Set.of(
UUID.randomUUID(),
UUID.randomUUID()
));
// Throw Error: no viable alternative at input '<EOF>' (SELECT * FROM example WHERE [uuid] IN...)
return this.myRepository.findAllByUuidIn(Set.of());
So if not contain uuid:
Collection<UUID> search = Set.of();
if(search.size() == 0) {
return List.of();
}
return this.myRepository.findAllByUuidIn(search);
(I am adding this answer for future reference)
I had the same error when running a spark application.
The error occurred when executing a Cassandra query and where a UUID type was expected, some other data type was sent by the query. In my case, it was a String. Passing the right data type (UUID instead of String) resolved the issue.
I hope you found an answer, but if you are using UUID version 4, maybe the type in your table are wrong. For example instead of UUID your ID field could be varchar.
I have a native sql query as the following :
for (init i=0; i<=2 ; i++) {
String sql = "Select * from accounts where id = ?";
Query query = em.createNativeQuery(sql,AccountBean.class);
query.setParameter(1, i );
AccountBean accountBean = (AccountBean)query.getSingleResult();
}
For the first loop it works correctly but any loop after the first one returns the same result as the first one , i debug it, the parameter changed , it works correctly if i change
Query query = em.createNativeQuery(sql,AccountBean.class);
to
Query query = em.createNativeQuery(queryString);
Regards
Wish79
Every JPA entity must have a primary key. Your JPA entities may not properly reflect the primary key, if any, on the database table.
I ran into the same problem. In my model class I had only one class variable annotated with #Id. However, that was not an accurate reflection of the table itself, which has a composite primary key. Thus, my query results returned the correct number of rows, but each confoundingly contained the same values, even though the actual data was different in the db. For example, this query:
Query query = entityManager.createQuery
("SELECT tbl FROM Tbl tbl WHERE tbl.id = 100
and tbl.code in ('A','B','C')");
...returned 10 rows, each showing a code of 'A'. But in actuality 9 of those 10 rows had a different code value ('B' or 'C'). It seemed as if the results were being cached and/or the tbl.code predicate was ignored. (That happened whether I used JPQL or Native SQL.) Very confusing.
To fix this I added an additional #Id annotation to my model to reflect the composite primary key:
#Id
#Column(name = "Code")
public String getCode() {
return this.code;
}
Now the query returns the data correctly and the code select criteria is no longer effectively ignored.
Edit: Although the above worked for me, on further research it seems a better approach to configure a separate JPA Entity composite primary key class. See http://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cmp30cfg001.htm.
For example, here's an Entity class with an embedded primary key (see #EmbeddedId):
/**
* The persistent class for the SOME_TABLE database table.
*/
#Entity
#Table(name = "SOME_TABLE")
public class SomeTable implements Serializable {
#EmbeddedId
private SomeTablePk id;
#Column(name = "NUMBER_HRS")
private BigDecimal numberHrs;
...
...and here's the composite primary key class (see #Embeddable):
#Embeddable
public class SomeTablePk implements Serializable {
#Column(name = "SOME_ID")
private String someId;
#Column(name = "ANOTHER_ID")
private BigDecimal anotherId;
public String getSomeId() {
return someId;
}
...
I'm having a problem with an HQL query
Three classes
ClassOne is my BusinessObject
public class ClassOne {
private int id;
private int status;
private Set<ClassTwo> classTwos;
+ other fields/getters/setters/constructor etc
}
ClassTwo is referenced in a set of ClassOne and is kind of the history of an object of ClassOne
public class ClassTwo {
private int id;
private int oldStatus;
private int newStatus;
private String message;
//+ getters/setters/constructor etc
}
ClassThree is my DTO/VO with just one classTwo (not the whole history)
public class ClassThree {
private int id;
private int status;
private ClassTwo classTwo;
public ClassThree(int pId, int pStatus, ClassTwo pClassTwo) {
id=pId;
status=pStatus;
classTwo=pClassTwo;
}
//+ getters/setters etc
}
Now I'd like to create an HQL query like this:
I'd like to get all objects of ClassThree with a certain status and if it exists the newest ClassTwo with a certain newStatus.
For example:
I'd like to get all the DTOs (ClassThree) of ClassOne whose status is now 1, but earlier in their history it has been 2 and I'd like to have the latest ClassTwo object which has 2 as newStatus.
SELECT new ClassThree(c1.id, c1.status, c2)
FROM ClassOne c1
LEFT JOIN c1.classtwos c2 (...)
and (...) is where I don't know what to do, I'm not even sure if it's a join / join fetch
Looked around and tried quite a lot already, but no clue. Especially with the join fetch I get some Hibernate errors like org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list.
Fetching the BusinessObject like that is no problem
SELECT distinct(c1)
FROM ClassOne c1
LEFT OUTER JOIN FETCH c1.classtwos c2
and I get the ClassTwos as my field.
Thanks in advance,
Jacob
P.S.: One thing might be important, ClassTwo has no reference to ClassOne!!
P.P.S : The simple SQL query which resolves my problem looks more or less like that:
select * from classone as c1 left join (select * from classtwo where newstatus = 2) c2 on c1.id=c2.id_classone whete c1.status = 1
This query works and gets all the information needed on my PostGreSQL DB, but I'd really like to have an HQL to continue to work with, especially for maintenance reasons and so on...
Update with workaround solution:
Getting the ids of all the ClassOnes with a status 1
Collection<Integer> ids = null;
ids = (Collection<Integer>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session pSession) throws HibernateException, SQLException {
return getDocumentIds(pSession, pStatus);
}
}
);
Now I get all the DTOs which have been in status 2 (thanks to Ivan) with:
Named query Document.dto.with.transfer
SELECT new DocumentDTO(d.id, d.status, histo)
FROM Document d
LEFT JOIN d.histories histo
WHERE
d.id in (:ids)
AND
(histo.id =
SELECT MAX(innerhisto.id)
FROM Document innerd
JOIN innerd.histories innerhisto
WHERE d.id = innerd.id AND innerhisto.newStatus = 21)
(in my code I use some named queries)
List<DocumentDTO> lRes = new ArrayList<DocumentDTO>();
Query lQuery = getSession(false).getNamedQuery("Document.dto.with.transfer");
lQuery.setParameterList("ids", ids);
lResultList.addAll(lQuery.list());
afterwards I remove all the IDs already found from my list ids
for (DocumentDTO dto : lResultList) {
ids.remove(dto .getId());
}
I do a third query using a second constructor for the DTO, initializing my history with a dummy-object.
Named query Document.dto.simple
SELECT new DocumentDTO(d.id, d.status)
FROM Document d
WHERE
d.id in (:ids)
(another named query)
lQuery = getSession(false).getNamedQuery("Document.dto.simple");
lQuery.setParameterList("ids", ids);
lResultList.addAll(lQuery.list());
and it's done.
To include Documents with no history we should use LEFT JOIN and test for empty collection, then we use subquery (SELECT COUNT(...)) to detect all documents that have never been in status 2. The last OR-clause is for fetching the last history with the specified status.
Here is the HQL query:
SELECT new DocumentDto(doc.id, doc.status, hist)
FROM Document doc
LEFT JOIN doc.histories hist
WHERE doc.status = :docStatus
AND (size(doc.histories) = 0
OR (SELECT COUNT(innerhist)
FROM Document innerdoc JOIN innerdoc.histories innerhist
WHERE innerdoc.id=doc.id AND innerhist.newStatus = :historyStatus) = 0
OR (hist.newStatus = :historyStatus AND hist.id =
(SELECT max(innerhist.id)
FROM Document innerdoc
JOIN innerdoc.histories innerhist
WHERE innerdoc.status = :docStatus AND innerhist.newStatus = :historyStatus))
Then call setParameter("historyStatus", 2) and setParameter("docStatus", 1) on your query to get the correct result.
That's it!
Please note, I've made an assumption, that we can use a value of id attribute of History as an indicator of the order in which objects were put in your database.