【问题标题】:JPA Left Join IS NULL condition not workingJPA Left Join IS NULL 条件不起作用
【发布时间】:2016-08-13 00:39:11
【问题描述】:

我在 MySQL 上有 User 和 Employee 表,并且在 User 表中有 employeeId 作为外键。

现在我需要获取没有用户的员工。

我在 MySQL Workbench 中编写了这个 SQL,这正是我想要的:

SELECT * FROM HUMANRESOURCE.EMPLOYEE E LEFT JOIN AUTHORIZE.USER U 
                                       ON U.EMPLOYEEOBJID = E.OBJID  
                                       WHERE U.EMPLOYEEOBJID is NULL;

但是当我尝试将此 SQL 实现为 JPA 查询时,它什么也不返回。这是 JPA 查询:

Query query = em.createQuery("SELECT e FROM Employee e LEFT JOIN User u 
                                        WHERE u.employee.objid = e.objid 
                                        AND u.employee IS NULL");

这是真正有效的 JPA 查询,我用它来获取拥有用户的员工:

Query query = em.createQuery("SELECT e FROM Employee e INNER JOIN User u 
                                       WHERE u.employee.objid = e.objid");

我在这里做错了什么?

实体类更新:

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;
    }
}

Employee.java

package com.kadir.entity.humanresource;

import com.kadir.entity.corporation.Company;
import com.kadir.entity.Base;

import java.io.Serializable;

import javax.persistence.*;


/**
 * The persistent class for the EMPLOYEE database table.
 * 
 */
@Cacheable
@Entity
@Table(name = "EMPLOYEE", schema = "HUMANRESOURCE")
@NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")
public class Employee extends Base implements Serializable {
    private static final long serialVersionUID = 1L;

    @ManyToOne
    @JoinColumn(name = "COMPANYOBJID")
    private Company company;

    @Column(name = "FIRSTNAME")
    private String firstname;

    @Column(name = "GENDER")
    private int gender;

    @Column(name = "EMAIL")
    private String email;

    @Column(name = "PHONE")
    private String phone;

    @Column(name = "LASTNAME")
    private String lastname;

    public Employee() {
    }

    public Company getCompany() {
        return this.company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    public String getFirstname() {
        return this.firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public int getGender() {
        return this.gender;
    }

    public void setGender(int gender) {
        this.gender = gender;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return this.phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getLastname() {
        return this.lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

}

User.java

package com.kadir.entity.authorize;

import com.kadir.entity.Employee;
import com.kadir.entity.Base;
import java.io.Serializable;
import javax.persistence.*;


import java.util.List;


/**
 * The persistent class for the USER database table.
 * 
 */
@Cacheable
@Entity
@Table(name="USER", schema="AUTHORIZE")
@NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User extends Base implements Serializable {
    private static final long serialVersionUID = 1L;

    @OneToOne
    @JoinColumn(name="EMPLOYEEOBJID")
    private Employee employee;

    @Column(name="NAME")
    private String name;

    @Column(name="PASSWORD")
    private String password;

    public User() {
    }

    public Employee getEmployee() {
        return this.employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

【问题讨论】:

  • 基本上:您犯了将 SQL 转换为 JPQL 的常见错误,这是行不通的,因为它们绝对不一样。解决问题的唯一方法是尝试从您拥有的模型和您当前未显示的模型(JPA 实体)的角度来回答问题。如果 Employee 有一个到 User 的反向映射,那么这个问题就会变得非常简单。
  • Employee 没有反向映射,User 类中只有 Employee 对象。这种情况有什么解决方法还是我必须添加反向映射? @金比
  • 实体类可以同时看到吗?
  • 我用实体类@Zia编辑了问题
  • 尝试在查询中使用“IS EMPTY”而不是 IS NULL

标签: java jpa join eclipselink jpql


【解决方案1】:

EclipseLink 支持ON clause,因此请尝试使用

"SELECT e FROM Employee e LEFT JOIN User u on u.employee = e WHERE u.employee IS NULL"

你也可以使用exist和子查询:

"select e from Employee e where not exists (select 1 from User u where u.employee = e)"

【讨论】:

    【解决方案2】:

    就我而言,我使用的是 Apache OpenJPA

    查询应该是这样的:

    SELECT e FROM Employee e LEFT JOIN e.user u WHERE u.employeeId IS NULL
    

    【讨论】:

      【解决方案3】:

      我有类似的错误。我有条件的 OneToOne 关系。我解决了这样的问题。

          @Query("SELECT e FROM Employee e LEFT OUTER JOIN User u ON  u = e.user " +
              "WHERE (u IS NULL OR e.condition = :conditionValue) ")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-29
        • 1970-01-01
        • 1970-01-01
        • 2021-09-11
        • 2018-12-04
        • 1970-01-01
        • 1970-01-01
        • 2015-09-22
        相关资源
        最近更新 更多