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.
Related
I am studying at the university in my third year. We pass Spring and Hibernate. I am developing an application using Java and Hibernate.
It is not possible to check for the presence of a category, and create it if it is not found
Hello everyone, I am studying at the university in my third year. We pass Spring and Hibernate. I am developing an application using Java and Hibernate.
It is not possible to check for the presence of a category, and create it if it is not found
class Category
package oleg94.catalog.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.Collection;
import java.util.List;
#Entity
#Table(name = "category")
#Getter
#Setter
public class Category {
#Id
#SequenceGenerator(name = "IdCategory", sequenceName = "category_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "IdCategory")
private Long id;
private String name;
#OneToMany(mappedBy = "category")
private List<Product> products;
#OneToMany(mappedBy = "category")
private List<Characteristic> characteristics;
}
class CreateCategory
package oleg94.catalog;
import oleg94.catalog.entity.Category;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import java.util.List;
import java.util.Scanner;
public class CreateCategory {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("main");
EntityManager manager = factory.createEntityManager();
String temp;
System.out.println("Введите название категории:");
Scanner scanner = new Scanner(System.in);
try {
temp = scanner.nextLine();
TypedQuery<Category> categoryTypedQuery = manager.createQuery(
"select c from Category c where c.name like ?1", Category.class);
categoryTypedQuery.setParameter(1, "%" + temp + "%");
List<Category> categories = categoryTypedQuery.getResultList();
if (!categories.contains(temp)){
Category category = new Category();
category.setName(temp);
manager.persist(category);
} else {
System.out.println("Данная категория уже есть");
}
manager.getTransaction().commit();
} catch (Exception e) {
manager.getTransaction().rollback();
e.printStackTrace();
}
}
}
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'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 have two tables connected with many-to-many relationship. Database is set on another server and I see really big performance problem when I'm trying to get informations about one of the records if these informations include total count of the second table.
First bean:
package dbaccess.beans.newsletter;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
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.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Column;
import javax.persistence.Table;
import dbaccess.beans.RegisteredUser;
#Entity
#Table(name="NEWSLETTER_LIST")
public class NewsletterList {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "NEWSLETTER_LIST_SEQ", allocationSize = 1, initialValue= 1)
#Column(name = "LIST_ID", unique = true, nullable = false)
private Long listID;
#Column(name = "LIST_NAME", nullable = false, length = 50)
private String listName;
#ManyToMany(fetch = FetchType.LAZY, cascade = {})
#JoinTable(name = "NEWSLETTERLISTS_USERS", joinColumns = {
#JoinColumn(name = "LIST_ID", nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "USER_ID", nullable = false) })
private Set<RegisteredUser> users = new HashSet<RegisteredUser>(0);
public Long getListID() {
return listID;
}
public void setListID(Long listID) {
this.listID = listID;
}
public Set<RegisteredUser> getUsers() {
return users;
}
public void setUsers(Set<RegisteredUser> users) {
this.users = users;
}
}
Second bean:
package dbaccess.beans;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Column;
import javax.persistence.Table;
import dbaccess.beans.newsletter.NewsletterList;
#Entity
#Table(name="USER")
public class RegisteredUser {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "USER_SEQ", allocationSize = 1, initialValue= 1)
#Column(name = "USER_ID", unique = true, nullable = false)
private Long usrID;
#Column(name = "GIVENNAME", length = 20)
private String usrGivenName;
#Column(name = "FAMILYNAME", length = 20)
private String usrFamilyName;
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "users", cascade = {})
public Set<NewsletterList> newsletterList = new HashSet<NewsletterList>();
public Long getUsrID() {
return usrID;
}
public void setUsrID(Long usrID) {
this.usrID = usrID;
}
public String getUsrGivenName() {
return usrGivenName;
}
public void setUsrGivenName(String usrGivenName) {
this.usrGivenName = usrGivenName;
}
public String getUsrFamilyName() {
return usrFamilyName;
}
public void setUsrFamilyName(String usrFamilyName) {
this.usrFamilyName = usrFamilyName;
}
public Set<NewsletterList> getNewsletterList() {
return newsletterList;
}
public void setNewsletterList(Set<NewsletterList> newsletterList) {
this.newsletterList = newsletterList;
}
#Override
public String toString() {
return "RegisteredUser[usrID=" + usrID + ", usrGivenName=" + usrGivenName + ", usrFamilyName=" + usrFamilyName + "]";
}
}
And the problem is when I try to execute this piece of code:
session = dbService.getSessionFactory().openSession();
Criteria c = session.createCriteria(NewsletterList.class);
c.add(Restrictions.eq("listID", listID));
List<NewsletterList> newsletterList = (List<NewsletterList>) c.list();
//below is most expensive
newsletterList.get(0).getUsers().size()
Is there any way to improve this performance?
Thanks in advance.
PS When I have approx. 70 users in one list, request to above code takes approx 5-6 seconds!
newsletterList.get(0).getUsers().size() makes Hibernate load all the users registered to the newsletter, only to get the number of registered users.
Use an ad hoc HQL query to count the number of registered users:
select count(user.usrID) from RegisteredUser user
inner join user.newsletterList newsLetter
where newsLetter.listID = :listId
Note that 5-6 seconds to execute the above code is way too much, though. You probably need to check if there is an index placed on the join columns of the join table.
Also note that you could simply use session.get(NewsLetter.class, listId) to get the list by ID.
And finally, everything would be easier and more readable if your IDs were all named id.
You might want to try using the Hibernate Criteria API to query for the number of users on a specific newsletter. It would look roughly like this:
Criteria crit = session.createCriteria(RegisteredUser.class);
crit.setProjection(Projections.rowCount());
crit.add(Restrictions.eq("listID", listID));
return (Long) crit.uniqueResult();