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
)
Related
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 3 classes Player(PK Id_player), Match(PK Id_match) and Inscription(PK should be Id_player and Id_match). A Player has ONE and ONLY ONE inscription(1 Player-> 1 Inscription), and a Match can be in many inscriptions(1 Match -> Many inscriptcions). So the table Inscriptions have 2 foreig keys Id_player and Id_match, the problem is that I don't how to tell hibernate that both foreing keys must be a composed primarey key for Inscriptions Table. This is my code::
#Entity
#Table(name = "Players")
public class Player{
#Id #GeneratedValue
private Long Id_player;
#OneToOne
#JoinColumn(name = "payer_id")
Inscription Inscription;}
#Entity
#Table(name="Matches")
public class Match{
#Id #GeneratedValue
private long Id_match;
#OneToMany
#JoinColumn(name = "id_match")
List<Inscription> inscriptions= new ArrayList<>();
What should I write on Inscription class to make both Fk's a composed PK. Thanks
Check this :
Player
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "Players")
public class Player {
#Id
#GeneratedValue
private Long Id_player;
#OneToOne
private Match match;
}
Match
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="Matches")
public class Match{
#Id #GeneratedValue
private long Id_match;
#OneToMany
#JoinTable(name="Inscription",
joinColumns=#JoinColumn(name="MATCH_ID"),
inverseJoinColumns=#JoinColumn(name="PLAYER_ID"))
private List<Player> playersList;
public long getId_match() {
return Id_match;
}
public void setId_match(long id_match) {
Id_match = id_match;
}
public List<Player> getPlayersList() {
return playersList;
}
public void setPlayersList(List<Player> playersList) {
this.playersList = playersList;
}
}
I Have 2 tables
1.User
2.Company
For each user there is a company. For each company it can multiple users.
UserBean.java
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
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.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
#Entity
#Table(name = "tab_user")
public class UserBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "user_id")
private int user_id;
#Column(name="user_login_pwd")
private String user_login_pwd;
#ManyToOne
#JoinColumn(name="comp_id")
private CompanyBean companyBean
And my CompanyBean is
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
#Entity
#Table(name = "tab_company")
public class CompanyBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "comp_id")
private Integer comp_id;
#Column(name = "comp_code")
private String comp_code;
#OneToMany(mappedBy = "companyBean" , fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(value = FetchMode.SUBSELECT)
private List<UserBean> companyUserList;
This is my CompanyBean mapping class.
Now i need to show list of users order by 'comp_code'. My DAO implementation for users list is
#SuppressWarnings("unchecked")
#Override
public List<UserBean> getUserList( String orderBy, String orderField) throws Exception{
List<UserBean> userList = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try{
Criteria crit = session.createCriteria(UserBean.class);
if(orderBy.equals("asc")){
crit.addOrder(Order.asc(orderField));
}else{
crit.addOrder(Order.desc(orderField));
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
userList = crit.list();
}finally{
session.close();
}
return userList;
}
So how can i get order by comp_code of CompanyBean in usersList? Please help.
No Hibernate solution is to create your own Comparator and to order with Collections.sort;
Hibernate solution is using of #OrderBy annotation.
Using hibernate with annotations, i want a one-many relationship to be sorted
By creating alias for beans we can get orderBy from manyToOne field
#SuppressWarnings("unchecked")
#Override
public List<UserBean> getUserList( String orderBy, String orderField) throws Exception{
List<UserBean> userList = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try{
Criteria crit = session.createCriteria(UserBean.class,"user").createAlias("user.companyBean", "company");
/*If my order field is from company bean then it should be company.company_field*/
if(orderBy.equals("asc")){
crit.addOrder(Order.asc(orderField));
}else{
crit.addOrder(Order.desc(orderField));
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
userList = crit.list();
}finally{
session.close();
}
return userList;
}
I'm using a GlassFish 4.0 server and server-sided JPA-based classes, which I want to deliver via JAX-RS. This works fine so far for simple entities. However, if I have a #OneToMany relation for example AND there is a linked entity, the server returns a 500 internal server error. In that case, nothing is logged to the server log. In order to find the error, I created a small custom JSP page to get more info about what happened. The code is just this:
Status: <%= pageContext.getErrorData().getStatusCode() %>
Throwable: <%= pageContext.getErrorData().getThrowable() %>
Unfortunately, the output is just "Status: 500 Throwable: null"
My own server-sided code seems to run properly (did some debug output), but however, some error emerges. In this example, the User and Issue classes can be retrieved without a problem unless there is a linked IssueComment entity:
User class:
package my.application.model;
import static javax.persistence.FetchType.LAZY;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
/**
* The persistent class for the User database table.
*
*/
#XmlRootElement
#Entity(name="User")
#Table(name="User")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="failedLogin")
private short failedLogin;
#Column(name="firstname")
private String firstname;
#Column(name="lastname")
private String lastname;
#Column(name="middlename")
private String middlename;
#Column(name="password")
private String password;
#Column(name="username")
private String username;
//bi-directional many-to-one association to IssueComment
#OneToMany(mappedBy="user", fetch = LAZY)
private List<IssueComment> issueComments;
//bi-directional many-to-one association to SignalComment
#OneToMany(mappedBy="user", fetch = LAZY)
private List<SignalComment> signalComments;
//bi-directional many-to-one association to SignalMeasure
#OneToMany(mappedBy="user", fetch = LAZY)
private List<SignalMeasure> signalMeasures;
public User() {
}
public int getId() {
return this.id;
}
// more getters and setters auto-generated by Eclipse
}
User class:
package my.application.model;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
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;
#NamedQuery(
name = "getSingleIssue",
query = "SELECT i FROM Issue i WHERE i.id = :id"
)
/**
* The persistent class for the Issue database table.
*
*/
#XmlRootElement
#Entity(name="Issue")
#Table(name="Issue")
public class Issue implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="concernedModule")
private String concernedModule;
#Column(name="createdate")
#Temporal(TemporalType.TIMESTAMP)
private Date createdate;
#Column(name="duedate")
#Temporal(TemporalType.TIMESTAMP)
private Date duedate;
#Column(name="priority")
private int priority;
#Column(name="reminderdate")
#Temporal(TemporalType.TIMESTAMP)
private Date reminderdate;
#Column(name="responsibleUserId")
private int responsibleUserId;
#Column(name="sendingModule")
private String sendingModule;
#Column(name="severity")
private int severity;
#Column(name="status")
private int status;
#Column(name="title")
private String title;
// bidirectional many-to-one association to IssueComment
#OneToMany(mappedBy = "issue")
private List<IssueComment> issueComments;
public Issue() {
}
public int getId() {
return this.id;
}
// more getters and setters....
}
IssueComment:
package my.application.model;
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
/**
* The persistent class for the IssueComment database table.
*
*/
#Entity(name="IssueComment")
#Table(name="IssueComment")
public class IssueComment implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
private int id;
#Lob
#Column(name="comment")
private String comment;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="time")
private Date time;
//bi-directional many-to-one association to Issue
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="issueId")
private Issue issue;
//bi-directional many-to-one association to User
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="userId")
private User user;
public IssueComment() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
// getters/setters....
}
The Webservice is as follows:
package my.application.server.webservice;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.glassfish.jersey.server.ResourceConfig;
import my.application.data.UserStorage;
import my.application.logger.Logger;
import my.application.model.Signal;
import my.application.model.SignalComment;
import my.application.model.User;
#Provider
#Path("User")
public class UserService extends ResourceConfig {
private UserStorage storage = new UserStorage();
public UserService() {
this.packages("my.application.model");
}
#Produces(MediaType.APPLICATION_XML)
#Path("load")
#GET
public User getUser(#QueryParam("id") int id) {
try {
Logger.getInstance().log("fetching id: " + id);
User u = storage.getUser(id);
Logger.getInstance().log("number of signal comments: " + u.getSignalComments().size());
SignalComment sc = u.getSignalComments().get(0);
Logger.getInstance().log("Signal 0 comment: " + sc.getComment());
Signal s = sc.getSignal();
Logger.getInstance().log("Signal subject: " + s.getSubject());
return u;
} catch (Exception e) {
e.printStackTrace();
}
// this code is not being reached (so no errors in this method):
Logger.getInstance().log("---EXCEPTION HAS BEEN THROWN---");
return null;
}
}
I left away the client source code since it's server-sided and can be reproduced with a normal browser, so no necessity for client code here IMHO.
Make sure you don't have any cyclic references in graph (objects) you're trying to marshall to XML. For example, this could cause a problem:
User -> IssueComment -> (the same) User
or
User -> IssueComment -> Issue -> IssueComment -> (the same) User
Such structures cannot be marshalled into XML.
Note: Add #XmlRootElement annotation to IssueComment (I think it's not needed but it's better to have it there).
Note: We know about the logging issue and it will be solved as a part of JERSEY-2000.
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.