虽然这个JPQL没有任何异常
Query query = em.createQuery("SELECT DISTINCT(r) FROM Request r LEFT JOIN Requesthistory h
WHERE h.request = r
AND (r.responsible = :employee OR h.employee = :employee)
AND r.requestedby != :employee ORDER BY r.objid DESC");
此JPQL无法正常工作并抛出NullPointerException
Query query = em.createQuery("SELECT DISTINCT(r) FROM Request r LEFT JOIN Requesthistory h
ON h.request = r
WHERE (r.responsible = :employee OR h.employee = :employee)
AND r.requestedby != :employee ORDER BY r.objid DESC");
这两个JPQL之间的唯一区别是ON Clause。
是的,实体和表格中的Request和Requesthistory之间存在1:N关系。
这是我得到的例外:
Exception Description: Query failed to prepare, unexpected error occurred: [java.lang.NullPointerException].
Internal Exception: java.lang.NullPointerException
Query: ReportQuery(referenceClass=Request jpql="SELECT DISTINCT(r) FROM Request r LEFT JOIN Requesthistory h ON h.request = r WHERE (r.responsible = :employee OR h.employee = :employee) AND r.requestedby != :employee ORDER BY r.objid DESC")
at org.eclipse.persistence.exceptions.QueryException.prepareFailed(QueryException.java:1590) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:680) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:901) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:613) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:194) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:116) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:102) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:86) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1603) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at com.kadir.dao.notification.RequestDao.findToUserRequests(RequestDao.java:44) [classes:]
at com.kadir.service.notification.RequestService.getToUserRequests(RequestService.java:43) [classes:]
at com.kadir.bean.notification.RequestBean.init(RequestBean.java:49) [classes:]
... 110 more
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.internal.expressions.ObjectExpression.getOwnedTables(ObjectExpression.java:583) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.FieldExpression.validateNode(FieldExpression.java:294) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.expressions.Expression.normalize(Expression.java:3275) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.DataExpression.normalize(DataExpression.java:369) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.FieldExpression.normalize(FieldExpression.java:223) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.CompoundExpression.normalize(CompoundExpression.java:224) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.RelationExpression.normalize(RelationExpression.java:574) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.RelationExpression.normalize(RelationExpression.java:865) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.expressions.ExpressionBuilder.normalize(ExpressionBuilder.java:267) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.RelationExpression.normalize(RelationExpression.java:825) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.CompoundExpression.normalize(CompoundExpression.java:232) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.CompoundExpression.normalize(CompoundExpression.java:224) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.expressions.SQLSelectStatement.normalize(SQLSelectStatement.java:1449) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.buildReportQuerySelectStatement(ExpressionQueryMechanism.java:641) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.buildReportQuerySelectStatement(ExpressionQueryMechanism.java:586) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.prepareReportQuerySelectAllRows(ExpressionQueryMechanism.java:1694) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.queries.ReportQuery.prepareSelectAllRows(ReportQuery.java:1203) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.queries.ReadAllQuery.prepare(ReadAllQuery.java:744) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.queries.ReportQuery.prepare(ReportQuery.java:1071) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:661) [eclipselink.jar:2.5.2.v20140319-9ad6abd]
... 120 more
我做错了什么?
更新实体
Request.java
package com.kadir.entity.notification;
import com.kadir.entity.Base;
import com.kadir.entity.humanresource.Employee;
import java.io.Serializable;
import javax.persistence.*;
import java.util.List;
/**
* The persistent class for the REQUEST database table.
*
*/
@Cacheable
@Entity
@Table(name="REQUEST", schema="NOTIFICATION")
@NamedQuery(name="Request.findAll", query="SELECT r FROM Request r")
public class Request extends Base implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name="CONTENT")
private String content;
@ManyToOne
@JoinColumn(name="REQUESTEDBY")
private Employee requestedby;
@ManyToOne
@JoinColumn(name="RESPONSIBLEOBJID")
private Employee responsible;
@Column(name="TITLE")
private String title;
//bi-directional many-to-one association to Requesttype
@ManyToOne
@JoinColumn(name="REQUESTTYPEOBJID")
private Requesttype requesttype;
//bi-directional many-to-one association to Responsetype
@ManyToOne
@JoinColumn(name="RESPONSETYPEOBJID")
private Responsetype responsetype;
//bi-directional many-to-one association to Requesthistory
@OneToMany(mappedBy="request")
private List<Requesthistory> requesthistories;
public Request() {
}
public String getContent() {
return this.content;
}
public void setContent(String content) {
this.content = content;
}
public Employee getRequestedby() {
return this.requestedby;
}
public void setRequestedby(Employee requestedby) {
this.requestedby = requestedby;
}
public Employee getResponsible() {
return this.responsible;
}
public void setResponsible(Employee responsible) {
this.responsible = responsible;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public Requesttype getRequesttype() {
return this.requesttype;
}
public void setRequesttype(Requesttype requesttype) {
this.requesttype = requesttype;
}
public Responsetype getResponsetype() {
return this.responsetype;
}
public void setResponsetype(Responsetype responsetype) {
this.responsetype = responsetype;
}
public List<Requesthistory> getRequesthistories() {
return this.requesthistories;
}
public void setRequesthistories(List<Requesthistory> requesthistories) {
this.requesthistories = requesthistories;
}
public Requesthistory addRequesthistory(Requesthistory requesthistory) {
getRequesthistories().add(requesthistory);
requesthistory.setRequest(this);
return requesthistory;
}
public Requesthistory removeRequesthistory(Requesthistory requesthistory) {
getRequesthistories().remove(requesthistory);
requesthistory.setRequest(null);
return requesthistory;
}
}
RequestHistory.java
package com.kadir.entity.notification;
import com.kadir.entity.humanresource.Employee;
import com.kadir.entity.Base;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the REQUESTHISTORY database table.
*
*/
@Cacheable
@Entity
@Table(name="REQUESTHISTORY", schema="NOTIFICATION")
@NamedQuery(name="Requesthistory.findAll", query="SELECT r FROM Requesthistory r")
public class Requesthistory extends Base implements Serializable {
private static final long serialVersionUID = 1L;
@ManyToOne
@JoinColumn(name="EMPLOYEEOBJID")
private Employee employee;
@Column(name="EXPLANATION")
private String explanation;
//bi-directional many-to-one association to Request
@ManyToOne
@JoinColumn(name="REQUESTOBJID")
private Request request;
//bi-directional many-to-one association to Responsetype
@ManyToOne
@JoinColumn(name="RESPONSETYPEOBJID")
private Responsetype responsetype;
public Requesthistory() {
}
public Employee getEmployee() {
return this.employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public String getExplanation() {
return this.explanation;
}
public void setExplanation(String explanation) {
this.explanation = explanation;
}
public Request getRequest() {
return this.request;
}
public void setRequest(Request request) {
this.request = request;
}
public Responsetype getResponsetype() {
return this.responsetype;
}
public void setResponsetype(Responsetype responsetype) {
this.responsetype = responsetype;
}
}
Base.java
package com.kadir.entity;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.Date;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
@Cacheable
@MappedSuperclass
public abstract class Base {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "OBJID")
private BigInteger objid;
@Column(name = "CREATEDBY")
private String createdby;
@Column(name = "CREATEDDATE")
private Timestamp createddate;
@Version
@Column(name = "ROWVERSION")
private Integer rowversion;
@Column(name = "UPDATEDBY")
private String updatedby;
@Column(name = "UPDATEDDATE")
private Timestamp updateddate;
@Column(name = "ARCHIVED", columnDefinition = "int default 0")
private int archived;
public BigInteger getObjid() {
return this.objid;
}
public void setObjid(BigInteger objid) {
this.objid = objid;
}
public String getCreatedby() {
return this.createdby;
}
public void setCreatedby(String createdby) {
this.createdby = createdby;
}
public Date getCreateddate() {
return this.createddate;
}
public void setCreateddate(Timestamp createddate) {
this.createddate = createddate;
}
public Integer getRowversion() {
return this.rowversion;
}
public void setRowversion(Integer rowversion) {
this.rowversion = rowversion;
}
public String getUpdatedby() {
return this.updatedby;
}
public void setUpdatedby(String updatedby) {
this.updatedby = updatedby;
}
public Timestamp getUpdateddate() {
return this.updateddate;
}
public void setUpdateddate(Timestamp updateddate) {
this.updateddate = updateddate;
}
public int getArchived() {
return archived;
}
public void setArchived(int archived) {
this.archived = archived;
}
}
答案 0 :(得分:1)
我认为问题在于您的继承映射。
映射的超级类Base
没有定义继承策略,因此默认使用一个SINGLE_TABLE。接下来,在每个子库@Table(name="...")
和Request
上定义Requesthistory
注释使用SINGLE_TABLE策略没有意义,因为此策略将所有子类映射到一个共享表。
我认为TABLE_PER_CLASS是你想要的策略。
@Cacheable
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Base {
在jpql中,join子句在sql中使用有点不同。您不能加入任意实体,然后通过ON或WHERE子句绑定它们。您只能加入与抽象模式关联的实体。
尝试以下(jpql valid)查询:
SELECT DISTINCT(r)
FROM Request r
LEFT JOIN r.requesthistories h
WHERE (r.responsible = :employee OR h.employee = :employee)
AND r.requestedby != :employee
ORDER BY r.objid DESC
(注意:非关联实体的查询是可行的,但它是不同的主题。)