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
Related
When using Hibernate GenerationType.Table strategy, do we need to have a table already created in the database for key generation, or can Hibernate create one by itself if no data is provided?
I have searched it on the internet and couldn't find a satisfactory answer.
In my code, when using AUTO type,it selects Table strategy which throws an exception that has something to do with the absence of a table for key generation in MySQL db. Just needed to confirm if it is the expected behaviour.
ERROR
DEBUG - select tbl.next_val from hibernate_sequences tbl where tbl.sequence_name=? for update
ERROR - HHH000351: Could not read or init a hi value
java.sql.SQLSyntaxErrorException: Table 'ifinances.hibernate_sequences' doesn't exist
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:955)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1005)
at org.hibernate.id.enhanced.TableGenerator.executeQuery(TableGenerator.java:705)
at org.hibernate.id.enhanced.TableGenerator.access$400(TableGenerator.java:132)
at org.hibernate.id.enhanced.TableGenerator$1$1.execute(TableGenerator.java:589)
at org.hibernate.id.enhanced.TableGenerator$1$1.execute(TableGenerator.java:575)
at org.hibernate.jdbc.WorkExecutor.executeReturningWork(WorkExecutor.java:55)
at org.hibernate.jdbc.AbstractReturningWork.accept(AbstractReturningWork.java:34)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:57)
at org.hibernate.id.enhanced.TableGenerator$1.getNextValue(TableGenerator.java:574)
at org.hibernate.id.enhanced.NoopOptimizer.generate(NoopOptimizer.java:40)
at org.hibernate.id.enhanced.TableGenerator.generate(TableGenerator.java:570)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:119)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:191)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:176)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:712)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:704)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:699)
at com.infiniteskills.data.Application.main(Application.java:42)
ERROR - Table 'ifinances.hibernate_sequences' doesn't exist
Entity class
#Entity
#Table(name = "BANK")
public class Bank {
#Id
/*
* #GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
*
* #GenericGenerator(name = "native", strategy = "native")
*/
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "BANK_ID")
private Long bankId;
#Column(name = "NAME")
private String name;
#Embedded
private Address address = new Address();
application class
package com.infiniteskills.data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import org.hibernate.Session;import org.hibernate.type.descriptor.java.LocalDateJavaDescriptor;
import com.infiniteskills.data.entities.Bank;
import com.infiniteskills.data.entities.TimeTest;
import com.infiniteskills.data.entities.User;
public class Application {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
try {
session.getTransaction().begin();
/*
* TimeTest test = new TimeTest(new Date()); session.save(test);
* session.getTransaction().commit();
*
* session.refresh(test);
*
* System.out.println(test);
*/
Bank bank = new Bank();
bank.setName("State Bank");
bank.setAddressLine1("Ranibagh");
bank.setAddressLine2("Haldwani");
bank.setCity("Nainital");
bank.setState("UK");
bank.setZipCode("63139");
bank.setCreatedBy("Vaibhav Pandey");
bank.setLastUpdatedBy("Vaibhav Pandey");
bank.setCreatedDate(LocalDateTime.now());
bank.setLastUpdatedDate(LocalDateTime.now());
bank.setInternational(false);
session.save(bank);
session.getTransaction().commit();
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 read several questions with answers about PostgreSQL, Hibernate and UUIDs, but none was about this precise issue I face.
Check this domain entity:
import java.io.Serializable;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
#Entity
#Table(name = "message")
public class Message implements Serializable {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "my.UUIDGenerator")
#Type(type = "pg-uuid")
#Column(name = "id", columnDefinition = "uuid")
private UUID id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "account")
private Account account;
#Type(type = "pg-uuid")
#Column(name = "user_created")
private UUID userCreated;
#Column(name = "message", columnDefinition = "text")
private String message;
}
I want to query it with this SQL query:
StatelessSession session = sessionFactory.openStatelessSession();
sql = "select "
+ "cast(id as varchar) as \"id\" " // ugly, but works
// + "id " // does not work, produces o.h.MappingException: No Dialect mapping for JDBC type: 1111
+ "from message m "
+ "where m.account = :account "
+ "and m.chat = :chatId ";
SQLQuery query = session.createSQLQuery(sql);
query.setParameter("account", accountId);
query.setParameter("chatId", chatId);
query.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String, Object>> result = query.list();
session.close();
As indicated in the code, returning the UUID does not work.
The only (bad) way to get the value returned is to cast it to a varchar.
The dialect Hibernate uses is configured like this:
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
For information completeness, the database table is defined like this:
create table message (
id uuid not null,
user_created uuid,
message text,
account uuid,
chat uuid
);
alter table public.message add constraint message_pkey primary key (id);
I use the following environment:
Linux 4.8.14
OpenJDK Runtime Environment (build 1.8.0_111-b16)
PostgreSQL 9.5.5
Hibernate 5.0.11.Final
Spring Boot 1.4.2.RELEASE
In my case this works
List<String> messageIdStringArrayList
= currentSession().createSQLQuery(String.format(
"select cast(m.id as varchar) " +
"from message m " +
"where m.account = '%s' " +
"and " +
"m.chat = '%s'",
String.valueOf(accountId), String.valueOf(chatId))).list();
List<UUID> messageIdArrayList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(messageIdStringArrayList)) {
for (String idString : messageIdStringArrayList) {
messageIdArrayList.add(UUID.fromString(idString));
}
}
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.
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.