I'm learning JPQL using simple Hibernate 5.0.4, Spring 4.2.3, Maven 3.3.3 based project on Oracle 11g XE. Full source code can be found on my GitHub branch.
I've got 2 models:
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity
#Table(name = "T_OWNER")
#NoArgsConstructor
public #Data class OwnerModel {
public OwnerModel(String firstName, String lastName, Integer age, OwnerType type) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.type = type;
this.since = new Date(System.currentTimeMillis());
this.age = age;
}
#Id
#GeneratedValue(generator = "owner-sequence-generator", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "owner-sequence-generator", sequenceName = "OWNER_SEQ", initialValue = 1, allocationSize = 20)
private Long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "TYPE")
#Enumerated(EnumType.STRING)
private OwnerType type;
#Column(name = "SINCE")
#Temporal(TemporalType.TIME)
private Date since;
#Column(name = "AGE")
private Integer age;
#OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = CarModel.class)
private List<CarModel> cars = new LinkedList<>();
public void addCar(CarModel car) {
cars.add(car);
car.setOwner(this);
}
}
import java.sql.Blob;
import java.sql.Clob;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
#Entity
#Table(name = "T_CAR")
#NoArgsConstructor
#AllArgsConstructor
#ToString(exclude = "owner")
public #Data class CarModel {
public CarModel(String name, Integer wheelsNumber, Clob spec, Blob image) {
super();
this.name = name;
this.wheelsNumber = wheelsNumber;
this.spec = spec;
this.image = image;
this.createdIn = new Date(System.currentTimeMillis());
}
#Id
#GeneratedValue(generator = "car-sequence-generator", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "car-sequence-generator", sequenceName = "CAR_SEQ", initialValue = 1, allocationSize = 20)
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "CREATED_IN")
#Temporal(TemporalType.TIMESTAMP)
private Date createdIn;
#Column(name = "WHEELS_NUMBER")
private Integer wheelsNumber;
#Lob
#Column(name = "SPEC")
private Clob spec;
#Lob
#Column(name = "IMAGE")
private Blob image;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = OwnerModel.class)
#JoinColumn(name = "ID_OWNER")
private OwnerModel owner;
}
They were used to prepare some data in my DB. When I execute such DAO located JPQL query:
#Override
public List<?> executeSelectWithGroupBy() {
return (List<?>) getSession().createQuery("select o, COUNT(c) from OwnerModel o LEFT JOIN o.cars c GROUP BY o").list();
}
I've got error as below :
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2116)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1899)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1875)
at org.hibernate.loader.Loader.doQuery(Loader.java:919)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336)
at org.hibernate.loader.Loader.doList(Loader.java:2611)
at org.hibernate.loader.Loader.doList(Loader.java:2594)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
at org.hibernate.loader.Loader.list(Loader.java:2418)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:501)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:371)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:226)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1268)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
at com.pduleba.spring.dao.OwnerDaoImpl.executeSelectWithGroupBy(OwnerDaoImpl.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy39.executeSelectWithGroupBy(Unknown Source)
at com.pduleba.spring.services.OwnerServiceImpl.executeSelectWithGroupBy(OwnerServiceImpl.java:40)
at com.pduleba.spring.controller.QueryControllerImpl.executeQueries(QueryControllerImpl.java:39)
at com.pduleba.hibernate.Main.execute(Main.java:50)
at com.pduleba.hibernate.Main.main(Main.java:27)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00979: not a GROUP BY expression
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:447)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:951)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:513)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:227)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:208)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:886)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1175)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1296)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3613)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3657)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1495)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:83)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:83)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
... 32 more
As far as I understand it is caused by error in Hibernate generated SQL :
select
ownermodel0_.id as col_0_0_,
count(cars1_.id) as col_1_0_,
ownermodel0_.id as id1_1_,
ownermodel0_.AGE as AGE2_1_,
ownermodel0_.FIRST_NAME as FIRST_NAME3_1_,
ownermodel0_.LAST_NAME as LAST_NAME4_1_,
ownermodel0_.SINCE as SINCE5_1_,
ownermodel0_.TYPE as TYPE6_1_
from
hibernate.T_OWNER ownermodel0_
left outer join
hibernate.T_CAR cars1_
on ownermodel0_.id=cars1_.ID_OWNER
group by
ownermodel0_.id
where GROUP BY clause should include all columns (not just id). In my opinion hibernate should generate such SQL :
select
ownermodel0_.id as col_0_0_,
count(cars1_.id) as col_1_0_,
ownermodel0_.id as id1_1_,
ownermodel0_.AGE as AGE2_1_,
ownermodel0_.FIRST_NAME as FIRST_NAME3_1_,
ownermodel0_.LAST_NAME as LAST_NAME4_1_,
ownermodel0_.SINCE as SINCE5_1_,
ownermodel0_.TYPE as TYPE6_1_
from
hibernate.T_OWNER ownermodel0_
left outer join
hibernate.T_CAR cars1_
on ownermodel0_.id=cars1_.ID_OWNER
group by
ownermodel0_.id,
ownermodel0_.AGE,
ownermodel0_.FIRST_NAME,
ownermodel0_.LAST_NAME,
ownermodel0_.SINCE,
ownermodel0_.TYPE;
However (as far as I understand) here and here are shown exactly the same JPQL Queries comparing to mine.
Is it a bug in Hibernate or just a hidden bug in my code?
I appreciate your help and advice.
It would not work for hibernate.
As you can see there is issue connected with this in Jira - https://hibernate.atlassian.net/browse/HHH-2436 and it's in unresolved state.
Links that you provided first is JPA spec and second one there is not group by model query but just by simple numeric field.
As #GingerHead answered it would be easier to modfiy your query
Let's better do this:
select
o.column1, o.column2, COUNT(c)
from
OwnerModel o
LEFT JOIN
o.cars c
GROUP BY
o.column1, o.column2
because count method destructs all the query notion
In all your references grouping is happening on simple fields, and aggregation is happening on simple fields - thus in proposed examples SQL will work.
It seems like a problem with your code, you are trying to fetch an EAGER loaded collection, as part of GROUP BY.
Nevertheless your List<CarModel> is always prepopulated (it is marked as EAGER) - so to get the count simply get the length of your list once your OwnerModel entity is loaded.
I would recommend to rework your Model and DAO layer in order to remove #OneToMany List<CarModel> cars field from OwnerModel. If you always need the count on available CarModels just add this field to your OwnerModel entity as #Formula expression.
Related
There is an reccuring issue with my Spring Boot application (using Oracle Java 8, Hibernate and Oracle DB).
I have following error in the logs:
WARN o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - SQL Error: 1, SQLState: 23000
ERROR o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - ORA-00001: unique constraint (MY_SCHEMA.SYS_C0057302) violated
This constraint (SYS_C0057302) is UUID being UNIQUE. (UUID VARCHAR2(32) NOT NULL UNIQUE)
I cannot provoke this behaviour running it locally (even with load tests) - locally on windows it looks fine, but on RHEL (where it is deployed) problem occurs all the time.
Note that I have dozen more entity classes which all have UUIDs, but only this class is generating such strange duplicates all the time.
No idea how to fix it. Cannot find root cause of this.
Examples of UUIDsand classes used below:
There is a bit of normal UUIDs at the start, but after some time strange and duplicated UUIDs are being created. On 2 different RHEL envs.
Examples of normal UUIDs:
0C34561DD75D422CAD652715DF6C6E75
0CB86A03945040B9886752CC07EB116E
0DAA1A3AF2B5438F8CB9489348A92223
0EAE079E621B4D2B8E8BE445F76B14C9
0FCF05797E7E40DE8D3A9D6A3B44AAE1
12DEBCAB53C94285A4C3FF32C5A0BF8E
132A877F404D44069F78D9B74DD4BDC9
1338A8CE09B14552B78CBAD640A3CF29
136310C44374412FB5B1B8FAF7E35330
Example of strange UUIDs generated by UUID.randomUUID() - 99% of UUIDs are like that, very similiar, with 3 as number that comes up a lot:
33333330333433363333333233333339
33333330333433363333333333333336
33333330333433363333333433333330
33333330333433363333333433333332
33333330333433363333333433333333
33333330333433363333333533333330
33333330333433363333333533333333
33333330333433363333333533333339
33333330333433363333333533343332
33333330333433363333333633333332
33333330333433363333333633333334
33333330333433363333333733333333
33333330333433363333333733343335
33333330333433363333333833333333
33333330333433363333333933333332
TaskEntity class:
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import ----DashboardTaskDto;
import ----SimpleUserDto;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name = "TASK")
#ToString
#EntityListeners(AuditingEntityListener.class)
#Slf4j
class TaskEntity {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TASK_SEQ")
#SequenceGenerator(sequenceName = "TASK_SEQ", allocationSize = 1, name = "TASK_SEQ")
#Id
private Long id;
#Column(name = "KKF")
private String kkf;
#EqualsAndHashCode.Include
private UUID uuid = UUID.randomUUID();
private String customerName;
private String assignedUserName;
private String assignedUserRole;
private int dpd;
private Boolean bgk;
private String courtProceedings;
private String name;
private LocalDateTime dueDate;
private LocalDateTime doneDate;
private BigDecimal totalLiabilities;
private Long issueActivityId;
private String userId;
#Enumerated(EnumType.STRING)
private TaskStatus status;
#CreatedDate
private LocalDateTime created;
#LastModifiedDate
private LocalDateTime modified;
#Builder
public TaskEntity(String kkf, String customerName, String assignedUserName, String assignedUserRole, int dpd, Boolean bgk, String courtProceedings, String name, LocalDateTime dueDate, LocalDateTime doneDate, BigDecimal totalLiabilities, Long issueActivityId, String userId, TaskStatus status, LocalDateTime created, LocalDateTime modified) {
this.kkf = kkf;
this.customerName = customerName;
this.assignedUserName = assignedUserName;
this.assignedUserRole = assignedUserRole;
this.dpd = dpd;
this.bgk = bgk;
this.courtProceedings = courtProceedings;
this.name = name;
this.dueDate = dueDate;
this.doneDate = doneDate;
this.totalLiabilities = totalLiabilities;
this.issueActivityId = issueActivityId;
this.userId = userId;
this.status = status;
this.created = created;
this.modified = modified;
}
Task repository class:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.repository.Repository;
import org.springframework.lang.Nullable;
import java.util.Optional;
interface TaskRepository extends Repository<TaskEntity, Long> {
TaskEntity save(TaskEntity from);
Optional<TaskEntity> findByIssueActivityId(Long id);
Page<TaskEntity> findAll(#Nullable Specification<TaskEntity> spec, Pageable pageable);
}
TaskCreator used for entity creation/updates:
class TaskCreator {
public TaskEntity from(IssueActivityEntity issueActivityEntity) {
IssueEntity issue = issueActivityEntity.getIssue();
CustomerEntity customer = issue.getCustomer();
UserEntity user = issueActivityEntity.getUser();
return TaskEntity.builder()
.kkf(customer.getKkf())
.customerName(customer.getCompanyName())
.assignedUserName(user.getName())
.assignedUserRole(user.getRole())
.dpd(issue.retrieveMaxDpd())
.bgk(customer.isBgk())
.courtProceedings(customer.getCourtProceedings())
.name(issueActivityEntity.getActivity().getStatus())
.dueDate(issueActivityEntity.getDueDate())
.doneDate(issueActivityEntity.getDoneDate())
.totalLiabilities(customer.getTotalLiabilities())
.issueActivityId(issueActivityEntity.getId())
.status(issueActivityEntity.getStatus())
.userId(user.getId())
.build();
}
TaskEntity updateFrom(final TaskEntity task, final IssueActivityEntity ia) {
IssueEntity issue = ia.getIssue();
CustomerEntity customer = issue.getCustomer();
UserEntity user = ia.getUser();
task.setKkf(customer.getKkf());
task.setCustomerName(customer.getCompanyName());
task.setAssignedUserRole(user.getRole());
task.setDpd(issue.retrieveMaxDpd());
task.setBgk(customer.isBgk());
task.setCourtProceedings(customer.getCourtProceedings());
task.setName(ia.getActivity().getStatus());
task.setDueDate(ia.getDueDate());
task.setDoneDate(ia.getDoneDate());
task.setTotalLiabilities(customer.getTotalLiabilities());
task.setIssueActivityId(ia.getId());
task.setStatus(ia.getStatus());
task.setUserId(user.getId());
return task;
}
}
Update 1:
I tried setting -Djava.security.egd=file:/dev/./urandom but this did not help at all.
I have two entities: Car and Reservation. I would like to create named query with LEFT JOIN. I was trying to do this like it is described here How to create JPA query with LEFT OUTER JOIN but it doesn't work. Do you have any idea what is wrong in my query? I would like to show Cars which have NULL reservations. Anyway even with JOIN it does not work. After starting application I have an error:
Caused by: org.hibernate.HibernateException: Errors in named queries: Car.findAll
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:495) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
... 22 common frames omitted
In principle I would like to achieve this query which in MySQL works
SELECT distinct * FROM car c LEFT JOIN reservation r ON c.id = r.car_id WHERE c.producer='producer' AND c.model='model' AND c.type='type'
AND (r.date_of_rent < 'date1' AND r.date_of_return < 'date1') OR (r.date_of_rent > 'date2') OR r.date_of_rent IS NULL;
Car Entity
import java.io.Serializable;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
#Entity
#NamedQuery(name = "Car.findAll", query = "SELECT c FROM Car c LEFT JOIN c.reservation r WHERE c.producer=:producer "
+ "AND c.type=:type AND c.dailyPrice=:dailyPrice")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String producer;
private String model;
private int seatsNumber;
private String type;
private String registrationNumber;
private double dailyPrice;
private String description;
#OneToMany(mappedBy = "car")
private List<Reservation> reservations;
Reservation Entity
import java.io.Serializable;
import java.sql.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
#Entity
public class Reservation implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
private User user;
#ManyToOne
private Car car;
private Date dateOfRent;
private Date dateOfReturn;
Many thanks for help.
UPDATE
Problem solved. Query should look like this one
import java.io.Serializable;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
#Entity
#NamedQuery(name = "Car.findAll", query = "SELECT DISTINCT c FROM Car c LEFT JOIN c.reservations r WHERE "
+ "c.type=:type AND c.dailyPrice<=:dailyPrice AND ((r.dateOfRent < :dateOfRent AND r.dateOfReturn < :dateOfRent) OR "
+ "(r.dateOfRent > :dateOfReturn) OR (r.dateOfRent IS NULL))")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String producer;
private String model;
private Integer seatsNumber;
private String type;
private String registrationNumber;
private Double dailyPrice;
private String description;
#OneToMany(mappedBy = "car")
private List<Reservation> reservations;
SELECT c FROM Car c LEFT JOIN c.reservation r WHERE c.producer=:producer "
+ "AND c.type=:type AND c.dailyPrice=:dailyPrice
There is an error in this query c.reservation need to be changed to c.reservations.
I would like to show Cars which have NULL reservations.
You can't do it this way. Try to begin from this query:
select c from Car c where not exists (
select r.id from Reservation r where r.car.id = c.id
)
I have a mysql table summarized as under:
select * from transaction where workflow_id = 'A'\G
*************************** 1. row ***************************
transfer_id: 2
workflow_id: A
amount: 552
status: FAILED
instrument_type: Type-A
creation_date: 2016-02-29 12:11:05
initiation_date: 2016-02-29 12:43:23
completion_date: 2016-02-29 12:43:23
*************************** 2. row ***************************
transfer_id: 1
workflow_id: A
amount: 552
status: SUCCESS
instrument_type: Type-B
creation_date: 2016-03-01 10:25:22
initiation_date: 2016-03-01 10:25:23
completion_date: 2016-03-01 10:25:23
last_modified: 2016-03-01 10:25:23
The corresponding model for this transaction is as under:
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import com.limeroad.services.payments.xhr.CreateTransactionRequest;
import com.limeroad.services.payments.xhr.TransactionState;
import com.limeroad.commons.InstrumentType;
#Entity
#Table(name = "transaction")
public class Transaction implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6353431043455994887L;
public Transaction() {
}
#Id
#Column(name = "transfer_id")
private String transferId;
#Column(name = "workflow_id")
private String workflowId;
#Column(name = "amount")
private Double amount;
#Column(name = "status")
private String status;
#Enumerated(EnumType.STRING)
#Column(name = "instrument_type")
private InstrumentType instrumentType;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "creation_date")
private Date creationDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "initiation_date")
private Date initiationDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "completion_date")
private Date completionDate;
.........
}
I am currently trying to write a query for "given a workflowId, find the transaction having the maximum creation date"
I am using entityManager for writing the hql query.
The corresponding query is:
(ArrayList<Transaction>) entityManager
.createQuery(
"select a from Transaction a, "
+ "( select workflowId, max(creationDate) as maxCreationDate from Transaction t where t.workflowId in :workflowIds group by t.workflowId) as b"
+ " where a.workflowId=b.workflowId and a.creationDate = b.maxCreationDate ")
.setParameter("workflowIds", workflowIds).getResultList();
I get the following error when running this query
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ( near line 1, column 71 [select a from com.limeroad.services.payments.dao.model.Transaction a, ( select workflowId, max(creationDate) as maxCreationDate from com.limeroad.services.payments.dao.model.Transaction t where t.workflowId in :workflowIds group by t.workflowId) as b where a.workflowId=b.workflowId and a.creationDate = b.maxCreationDate ]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1750)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:331)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:293)
Please help
In HQL, Subquery as table is not possible.
HQL subqueries can occur only in the select or where clauses. It cannot be put as a table.
please refer this document https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch16.html#queryhql-subqueries
I am running spring jpa project and I have following class containing #ManyToOne relations:
package ba.fit.vms.pojo;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.springframework.format.annotation.DateTimeFormat;
#Entity
#Table(name="korisnik_vozilo")
public class KorisnikVozilo implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id;
#ManyToOne( cascade = {CascadeType.REFRESH}, fetch=FetchType.EAGER )
#JoinColumn(nullable=false, updatable=false)
private Vozilo vozilo;
#ManyToOne( cascade = {CascadeType.REFRESH}, fetch=FetchType.EAGER )
#JoinColumn(nullable=false, updatable=false)
private Korisnik korisnik;
#Column(name = "dodijeljeno")
#DateTimeFormat(pattern = "yyyy-MM-dd")
#NotNull
private Date dodijeljeno;
#Column(name = "vraceno")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date vraceno;
...
}
For some reason, starting the server, this code creates composite primary key (korisnik_id,vozilo_vin), instead of #Id defined primary key. Here is the screenshot of the table:
Can someone explain to me what did I do wrong and how to write this code so I do not get this composite key in the database, but the one defined in the class.
It even sets autoincrement on korisnik_id!
Try getting rid of updatable=false. being unupdatable, the two columns might be be viewed as an immutable identity of the entity.
You may check how you can use #JoinColumn to solve your problem.
I am using some entities generated by Netbeans. After generation I tested them and they were working fine. So then I had to move to my next step and combine those with my JAXB objects. After combining with the JAXB objects I am able to unmarshall my XML stream with no problem. But when I try to use any of those classes for anything entity related I get some errors.
I am back at the testing phase again now and here is what I have. I have a test class just running from a simple main method. The same setup I used to test the entities originally. Below you will see that test class, the Classes entity, The entity causing the issues JoinAssetToSku and the error. I have left out the majority of the setters and getters of the entities. Does anyone know what is wrong with this JoinAssetToSku.findByTs query. I do not understand how it causes that error, it is not self aware!?
The code to do the testing:
public void testClassEntity(){
testClass = new Classes(1);
testClass.setClassId("12");
testClass.setDescription("The First Class");
testClass.setTs(new java.sql.Timestamp(new Date().getTime()));
ClassesJpaController cc = new ClassesJpaController();
try {
cc.create(testClass);
} catch (PreexistingEntityException ex) {
Logger.getLogger(EntityTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(EntityTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
The Classes class:
package entitiesjaxb.cmic.ajrs.com;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Classes", propOrder = {
"pkId",
"classId",
"description",
"ts"
})
#Entity
#Table(name = "classes")
#NamedQueries({
#NamedQuery(name = "Classes.findAll", query = "SELECT c FROM Classes c"),
#NamedQuery(name = "Classes.findByPkId", query = "SELECT c FROM Classes c WHERE c.pkId = :pkId"),
#NamedQuery(name = "Classes.findByClassId", query = "SELECT c FROM Classes c WHERE c.classId = :classId"),
#NamedQuery(name = "Classes.findByDescription", query = "SELECT c FROM Classes c WHERE c.description = :description"),
#NamedQuery(name = "Classes.findByTs", query = "SELECT c FROM Classes c WHERE c.ts = :ts")})
public class Classes implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "pk_id")
private Integer pkId;
#Column(name = "class_id")
#XmlElement(name = "ClassID")
private String classId;
#Column(name = "description")
#XmlElement(name = "Description")
private String description;
#Basic(optional = false)
#Column(name = "ts")
#Temporal(TemporalType.TIMESTAMP)
#XmlElement(required = true)
#XmlSchemaType(name = "dateTime")
private Date ts;
#OneToMany(mappedBy = "classes", fetch = FetchType.LAZY)
#XmlTransient
private Collection<Categories> categoriesCollection;
public Classes() {
}
public Classes(Integer pkId) {
this.pkId = pkId;
}
public Classes(Integer pkId, Date ts) {
this.pkId = pkId;
this.ts = ts;
}
The class causing the error:
package entitiesjaxb.cmic.ajrs.com;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "JoinAssetToSKU", propOrder = {
"pkId",
"assetData",
"skuBasic",
"ts"
})
#Entity
#Table(name = "join_asset_to_sku")
#NamedQueries({
#NamedQuery(name = "JoinAssetToSku.findAll", query = "SELECT j FROM JoinAssetToSku j"),
#NamedQuery(name = "JoinAssetToSku.findByPkId", query = "SELECT j FROM JoinAssetToSku j WHERE j.pkId = :pkId"),
#NamedQuery(name = "JoinAssetToSku.findByTs", query = "SELECT j FROM JoinAssetToSku j WHERE j.ts = :ts")})
public class JoinAssetToSKU implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "pk_id")
private Integer pkId;
#Column(name = "ts")
#Temporal(TemporalType.TIMESTAMP)
#XmlElement(required = true)
#XmlSchemaType(name = "dateTime")
private Date ts;
#JoinColumn(name = "pk_sku", referencedColumnName = "pk_id")
#ManyToOne(fetch = FetchType.LAZY)
private SKUBasic skuBasic;
#JoinColumn(name = "pk_asset", referencedColumnName = "pk_id")
#ManyToOne(fetch = FetchType.LAZY)
private AssetData assetData;
public JoinAssetToSKU() {
}
public JoinAssetToSKU(Integer pkId) {
this.pkId = pkId;
}
public Integer getPkId() {
return pkId;
}
public void setPkId(Integer pkId) {
this.pkId = pkId;
}
The error I am getting.
[EL Info]: 2011-04-15 08:26:58.223--ServerSession(2128911821)--EclipseLink, version: Eclipse Persistence Services - 2.0.2.v20100323-r6872
[EL Severe]: 2011-04-15 08:26:58.525--ServerSession(2128911821)--Local Exception Stack:
Exception [EclipseLink-8034] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Error compiling the query [JoinAssetToSku.findByTs: SELECT j FROM JoinAssetToSku j WHERE j.ts = :ts]. Unknown entity type [JoinAssetToSku].
at org.eclipse.persistence.exceptions.JPQLException.entityTypeNotFound(JPQLException.java:483)
at org.eclipse.persistence.internal.jpa.parsing.ParseTreeContext.classForSchemaName(ParseTreeContext.java:138)
at org.eclipse.persistence.internal.jpa.parsing.SelectNode.getClassOfFirstVariable(SelectNode.java:327)
at org.eclipse.persistence.internal.jpa.parsing.SelectNode.getReferenceClass(SelectNode.java:316)
at org.eclipse.persistence.internal.jpa.parsing.ParseTree.getReferenceClass(ParseTree.java:439)
at org.eclipse.persistence.internal.jpa.parsing.ParseTree.adjustReferenceClassForQuery(ParseTree.java:79)
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.populateReadQueryInternal(JPQLParseTree.java:103)
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.populateQuery(JPQLParseTree.java:84)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:202)
at org.eclipse.persistence.internal.jpa.JPAQuery.processJPQLQuery(JPAQuery.java:106)
at org.eclipse.persistence.internal.jpa.JPAQuery.prepare(JPAQuery.java:90)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:464)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:430)
at org.eclipse.persistence.internal.sessions.AbstractSession.processJPAQueries(AbstractSession.java:1747)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:409)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:671)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:620)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:228)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:369)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:151)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:207)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:195)
at controllers.cmic.ajrs.com.ClassesJpaController.getEntityManager(ClassesJpaController.java:33)
at controllers.cmic.ajrs.com.ClassesJpaController.create(ClassesJpaController.java:42)
at cmicpojo.EntityTest.testClassEntity(EntityTest.java:33)
at cmicpojo.Main.main(Main.java:45)
[EL Info]: 2011-04-15 08:26:58.545--ServerSession(2128911821)--EclipseLink, version: Eclipse Persistence Services - 2.0.2.v20100323-r6872
Apr 15, 2011 8:26:58 AM cmicpojo.EntityTest testClassEntity
SEVERE: null
Local Exception Stack:
Exception [EclipseLink-7092] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Cannot add a query whose types conflict with an existing query. Query To Be Added: [ReadAllQuery(name="KeyFeatures.findByBasicDescription" referenceClass=KeyFeatures jpql="SELECT k FROM KeyFeatures k WHERE k.basicDescription = :basicDescription")] is named: [KeyFeatures.findByBasicDescription] with arguments [[class java.lang.String]].The existing conflicting query: [ReadAllQuery(name="KeyFeatures.findByBasicDescription" referenceClass=KeyFeatures jpql="SELECT k FROM KeyFeatures k WHERE k.basicDescription = :basicDescription")] is named: [KeyFeatures.findByBasicDescription] with arguments: [[class java.lang.String]].
at org.eclipse.persistence.exceptions.ValidationException.existingQueryTypeConflict(ValidationException.java:895)
at org.eclipse.persistence.internal.sessions.AbstractSession.addQuery(AbstractSession.java:388)
at org.eclipse.persistence.internal.sessions.AbstractSession.addQuery(AbstractSession.java:360)
at org.eclipse.persistence.internal.sessions.AbstractSession.processJPAQueries(AbstractSession.java:1749)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:409)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:671)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.login(DatabaseSessionImpl.java:633)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:214)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:195)
at controllers.cmic.ajrs.com.ClassesJpaController.getEntityManager(ClassesJpaController.java:33)
at controllers.cmic.ajrs.com.ClassesJpaController.findClasses(ClassesJpaController.java:174)
at controllers.cmic.ajrs.com.ClassesJpaController.create(ClassesJpaController.java:62)
at cmicpojo.EntityTest.testClassEntity(EntityTest.java:33)
at cmicpojo.Main.main(Main.java:45)
This was an error on my part, Combining the generated entities and generated JAXB classes led me to some classes named improperly.
The class name should be JoinAssetToSku to match the named query. Or I could leave the class name as JoinAssetToSKU and change the named query.
I chose to change the class name.