Not sure what I'm dong wrong so I'm guessing this is a bug. I'm trying to create a simple subquery but Eclipselink produces wrong SQL so the execution fails.
Error message
[EL Warning]: 2022-01-17 17:00:29.258--UnitOfWork(1407952056)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.9.v20200130-0143b822bc): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00904: "T1"."ID"."T1"."ID": invalid identifier
Error Code: 904
Call: SELECT COUNT(t0.ID) FROM Order t0 WHERE t0.OUTPUT IN (SELECT t1.ID.t1.ID FROM Process t1 WHERE (t1.OWNER = ?))
bind => [0]
Query: ReportQuery(referenceClass=Order sql="SELECT COUNT(t0.ID) FROM Order t0 WHERE t0.OUTPUT IN (SELECT t1.ID.t1.ID FROM Process t1 WHERE (t1.OWNER = ?))")
Sample code
EntityManager em = ApplicationContextListener.createEntityManager();
try {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<Order> root = cq.from(Order.class);
cq.select(cb.count(root));
// Process subquery
Subquery<Long> sqProcess = cq.subquery(Long.class);
Root<Process> sqProcessRoot = sqProcess.from(Process.class);
Path<Long> processId = sqProcessRoot.get("id");
sqProcess.select(processId)
.where(cb.equal(sqProcessRoot.get("owner"), cb.parameter(String.class, "person")));
cq.where(cb.in(root.get("processOutput")).value(sqProcess));
TypedQuery<Long> tq = em.createQuery(cq);
int count = tq.setParameter("person", loggedInPerson).getSingleResult().intValue();
log.debug("SQL count string: {}", tq.unwrap(JpaQuery.class).getDatabaseQuery().getSQLString());
log.debug("Count = {}", count);
} finally {
em.close();
}
Order
#Entity
#Table(name = "Order")
public class Order implements Serializable {
private static final long serialVersionUID = 2804475880693788686L;
#Id
#SequenceGenerator(name = "ORDER_ID_GENERATOR", sequenceName = "ORDER_SEQ", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ORDER_ID_GENERATOR")
private long id;
// bi-directional many-to-one association to Process
#ManyToOne
#JoinColumn(name = "OUTPUT")
private Process processOutput;
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public Process getProcessOutput() {
return this.processOutput;
}
public void setProcessOutput(Process processOutput) {
this.processOutput = processOutput;
}
}
Process
#Entity
#Table(name = "Process")
public class Process implements Serializable {
private static final long serialVersionUID = -2021620806203228247L;
#Id
#SequenceGenerator(name = "PROCESS_ID_GENERATOR", sequenceName = "PROCESS_SEQ", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PROCESS_ID_GENERATOR")
#Expose
private long id;
#ManyToOne
#JoinColumn(name = "OWNER")
private Person owner;
#XmlTransient
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
}
Related
Here my entity:
public class QdCF implements Diffable<QdCF> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "QDCF_ID")
private Integer id;
// #Column(name = "QDCF_AMBIT")
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "QDCF_AMBIT")
private String ambit;
}
Now, I've changed ambit field to ManyToOne:
public class QdCF implements Diffable<QdCF> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "QDCF_ID")
private Integer id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "QDCF_AMBIT")
private Ambit ambit;
}
Above code works fine.
However, I've a custom JPA criteria like this:
public static Specification<QdCF> likeCodi(String codi) {
return (root, criteriaQuery, criteriaBuilder) -> {
return criteriaBuilder.like(root.get(QdCF_.ambit).as(String.class), "%" + codi + "%");
};
}
Above code doesn't works now since:
Caused by: org.hibernate.QueryException: Expression to CAST cannot be an entity : qdcf0_.QDCF_AMBIT
Any ideas about how to troubleshot it?
Bidirectional ManyToMany mapping is using EMPLOYEE_PROJECT relation table instead of EMP_PROJ table described in mapping. EMPLOYEE_PROJECT does not exist on db. Eclipselink version is 2.7.3 and jpa version is 2.2
#Entity
public class Employee extends Base implements Serializable {
/** explicit set serialVersionUID */
private static final long serialVersionUID = 1L;
#Column(name = "FIRSTNAME")
private String firstname;
#ManyToMany
#JoinTable(name = "EMP_PROJ", joinColumns = #JoinColumn(name = "EMP_ID"), inverseJoinColumns = #JoinColumn(name = "PROJ_ID"))
private List<Project> projects;
public List<Project> getProjects() {
return projects;
}
public void setProjects(List<Project> projects) {
this.projects = projects;
Project Class
#Entity
public class Project extends Base implements Serializable {
/** explicit set serialVersionUID */
private static final long serialVersionUID = 1L;
#Column(name = "NAME")
private String name;
#ManyToMany(mappedBy="projects")
Set<Employee> employees = new HashSet<Employee>();
Problem is when query run
#Test
public void save_employee(){
EntityManager em = emf.createEntityManager();
Employee emp1 = em.find(Employee.class, new Integer(1));
Project p = new Project();
p.setName("Name1");
p.getEmployees().add(emp1);
p = em.merge(p);
assertNotNull(p);
Employee emp2 = em.find(Employee.class, new Integer(1));
assertEquals(1, emp2.getProjects().size());
em.close();
}
Following exception:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.3.v20180807-4be1041): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: Table "EMPLOYEE_PROJECT" not found; SQL statement:
SELECT t1.ID, t1.DESCRIPTION, t1.NAME, t1.VERSION FROM EMPLOYEE_PROJECT t0, PROJECT t1 WHERE ((t0.Employee_ID = ?) AND (t1.ID = t0.projects_ID)) [42102-197]
Error Code: 42102
Base.java code is as following
#MappedSuperclass
public class Base {
protected int id;
protected int version;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Version
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
}
I keep getting the following error with my Entity mappings.
Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: edu.indstate.ics.transcript.web.dao.entity.Swrhxml.swbhxml in edu.indstate.ics.transcript.web.dao.entity.Swbhxml.swrhxmls
I am not sure what I am doing wrong. Could use some insight and help on what I am missing here.
My Entity classes are as follows:
#Entity
#Table(name = "SWBHXML" )
public class Swbhxml implements DatabaseObject, Serializable {
private List<Swrhxml> swrhxmls;
private static final long serialVersionUID = 1L;
private Long swbhxmlTransId;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "SWBHXML_TRANS_ID", nullable = false)
public Long getSwbhxmlTransId() {
return swbhxmlTransId;
}
public void setSwbhxmlTransId(Long swbhxmlTransId) {
this.swbhxmlTransId = swbhxmlTransId;
}
#OneToMany(mappedBy = "swbhxml", cascade = CascadeType.ALL)
public List<Swrhxml> getSwrhxmls() {
return swrhxmls;
}
public void setSwrhxmls(List<Swrhxml> swrhxmls) {
this.swrhxmls = swrhxmls;
}
}
#Entity
#Table(name = "SWRHXML" )
public class Swrhxml implements DatabaseObject, Serializable {
private Swbhxml swbhxml;
private static final long serialVersionUID = 1L;
private Long SwrhxmlTransId;
private String SwrhxmlHxpsCode;
private Date SwrhxmlTimeStamp;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="SWBHXML_TRANS_ID")
public Swbhxml getSwrhxml() {
return swbhxml;
}
public void setSwrhxml(Swbhxml swbhxml) {
this.swbhxml = swbhxml;
}
#Column(name = "SWRHXML_HXPS_CODE", length = 15)
public String getSwrhxmlHxpsCode() {
return SwrhxmlHxpsCode;
}
public void setSwrhxmlHxpsCode(String SwrhxmlHxpsCode) {
this.SwrhxmlHxpsCode = SwrhxmlHxpsCode;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "SWRHXML_TIMESTAMP", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
public Date getSwrhxmlTimeStamp() {
return SwrhxmlTimeStamp;
}
public void setSwrhxmlTimeStamp(Date SwrhxmlTimeStamp) {
this.SwrhxmlTimeStamp = SwrhxmlTimeStamp;
}
}
You use
`mappedBy = "swbhxml"`
^
|___ b here
, but the annotated association is
Swbhxml getSwrhxml()
^
|___ r here
Your getter and setter are named incorrectly. And frankly, with such cryptic and close entity names, you'll probably have many such bugs.
I got a problem with JPA and ManyToMany association.
I got two class FOA_PARAM_EMPLOYE and FOA_PARAM_POSITION, and an association table FOA_PARAM_EMPLOYE_POSITION.
Class FoaParamEmploye :
#Entity
#Table(name = "FOA_PARAM_EMPLOYE")
#NamedQuery(name = "FoaParamEmploye.findAll", query = "SELECT f FROM FoaParamEmploye f")
public class FoaParamEmploye implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private FoaParamEmployePK id;
#Column(name = "ACTEUR_MAJ_OCCUR")
private String acteurMajOccur;
#Column(name = "ADRESSE_EMAIL")
private String adresseEmail;
// bi-directional many-to-many association to FoaParamPosition
#ManyToMany
#JoinTable(
name = "FOA_PARAM_EMPLOYE_POSITION",
joinColumns = { #JoinColumn(name = "ID_EMPLOYE"),
#JoinColumn(name = "COD_ENTREP") },
inverseJoinColumns = { #JoinColumn(name = "ID_POSITION")
})
private List<FoaParamPosition> foaParamPositions;
public FoaParamEmployePK getId() {
return this.id;
}
public void setId(FoaParamEmployePK id) {
this.id = id;
}
public String getActeurMajOccur() {
return this.acteurMajOccur;
}
public void setActeurMajOccur(String acteurMajOccur) {
this.acteurMajOccur = acteurMajOccur;
}
public String getAdresseEmail() {
return this.adresseEmail;
}
public void setAdresseEmail(String adresseEmail) {
this.adresseEmail = adresseEmail;
}
public List<FoaParamPosition> getFoaParamPositions() {
return foaParamPositions;
}
public void setFoaParamPositions(List<FoaParamPosition> pFoaParamPositions) {
this.foaParamPositions = pFoaParamPositions;
}
}
Class FoaParamPosition :
#Entity
#Table(name="FOA_PARAM_POSITION")
#NamedQuery(name="FoaParamPosition.findAll", query="SELECT f FROM FoaParamPosition f")
public class FoaParamPosition implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private FoaParamPositionPK id;
#Column(name="ACTEUR_MAJ_OCCUR")
private String acteurMajOccur;
#Column(name="CD_PROFIL_AFFECTATION")
private String cdProfilAffectation;
// bi-directional many-to-many association to FoaParamEmploye
#ManyToMany
private List<FoaParamEmploye> foaParamEmployes;
public FoaParamPositionPK getId() {
return this.id;
}
public void setId(FoaParamPositionPK id) {
this.id = id;
}
public String getActeurMajOccur() {
return this.acteurMajOccur;
}
public void setActeurMajOccur(String acteurMajOccur) {
this.acteurMajOccur = acteurMajOccur;
}
public String getCdProfilAffectation() {
return this.cdProfilAffectation;
}
public void setCdProfilAffectation(String cdProfilAffectation) {
this.cdProfilAffectation = cdProfilAffectation;
}
public List<FoaParamEmploye> getFoaParamEmployes() {
return foaParamEmployes;
}
public void setFoaParamEmployes(List<FoaParamEmploye> pFoaParamEmployes) {
this.foaParamEmployes = pFoaParamEmployes;
}
}
Table FOA_PARAM_EMPLOYE_POSITION has this columns :
COD_ENTREP
ID_EMPLOYE
ID_POSITION
XQCIF
ACTEUR_MAJ_OCCUR
DATE_HEURE_MAJ_OCCUR
I got this exception :
A Foreign key refering com.groupama.middlgan.entities.FoaParamPosition from
com.groupama.middlgan.entities.FoaParamEmploye has the wrong number of column.
should be 2
If I add COD_ENTREP on inverseJoinColumns in my FoaParamEmploye entity, I got this exception :
Repeated column in mapping for collection:
com.groupama.middlgan.entities.FoaParamEmploye.foaParamPositions column: COD_ENTREP
Any idee ?
[I am assuming you are listing the columns for the association table FOA_PARAM_EMPLOYE_POSITION, not FOA_PARAM_EMPLOYE, as you state in your question.]
Your mappings imply FOA_PARAM_EMPLOYE_POSITION.COD_ENTREP is part of two foreign keys, one referencing FOA_PARAM_EMPLOYE and one referencing FOA_PARAM_POSITION. In practice these two foreign keys might contain the same value for COD_ENTREP, but this cannot be enforced by the database or JPA.
You should probably model the relationship differently, possibly add another, container-like, object that has bi-directional one-to-many relationships with both FoaParamEmploye and FoaParamPosition and shares parts of its primary key with the other two primary keys.
If you want to keep your inverseJoinColumn mapping you can do as follows,
#ManyToMany
#JoinTable(
name = "FOA_PARAM_EMPLOYE_POSITION",
joinColumns = { #JoinColumn(name = "ID_EMPLOYE"),
#JoinColumn(name = "COD_ENTREP") }
,
inverseJoinColumns = {#JoinColumn(name = "FOAPARAMPOSITION_COD_ENTREP"), #JoinColumn(name = "FOAPARAMPOSITION_ID_POSITION")}
)
private List<FoaParamPosition> foaParamPosition;
and
#ManyToMany
#JoinTable(
name = "FOA_PARAM_EMPLOYE_POSITION",
joinColumns = { #JoinColumn(name = "ID_POSITION"),
#JoinColumn(name = "COD_ENTREP") }
,
inverseJoinColumns = {#JoinColumn(name = "FOAPARAMEMPLOYE_COD_ENTREP"), #JoinColumn(name = "FOAPARAMEMPLOYE_ID_EMPLOYE")}
)
private List<FoaParamEmploye> foaParamEmploye;
the mappings are aligned with the code you've posted in your other question JPA Many To Many Select
My provider is:
org.eclipse.persistence.jpa.PersistenceProvider
My Entity code is:
#Entity
#NamedQueries( { #NamedQuery(name = "Bank.findAll", query = "select o from Bank o") })
#Table(name = "B_BANK")
public class Bank implements Serializable {
private final static String ID_GENERATOR = "Bank";
private Long id;
private User modifier;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = ID_GENERATOR)
#SequenceGenerator(name = ID_GENERATOR, allocationSize = 1, sequenceName = "sq_B_BANK")
#Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "modifier")
public User getModifier() {
return modifier;
}
public void setModifier(User modifier) {
this.modifier = modifier;
}
}
And my test code is just:
entityManagerHelper = new EntityManagerHelper("Model", isAutoCommit);
List l = entityManagerHelper.getEntityManager().createQuery("select b from Bank b").getResultList();
However in my console I had this:
SELECT id, modifier FROM B_BANK
SELECT id, CREATION_DATE, MODIFICATION_DATE, modifier, creator FROM B_USER WHERE (id = ?)
bind => [2]
Therefore it seems that JPA queried for the User that I put fetch = FetchType.LAZY over it!
I am wondering why JPA queried for the User too.
Any help would be appreciated.
While the answer is true, EclipseLink uses weaving to implement lazy fetching for OneToOne and ManyToOne relationships. If you are not run in a container environment, then you would have to add in an agent or setup your entities to be statically woven to use lazy on 1:1s as described here: http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Dynamic_Weaving and here http://www.eclipse.org/eclipselink/documentation/2.4/concepts/app_dev007.htm