简体   繁体   English

JPA左联接查询

[英]JPA left join query

Given the following two tables: 给出以下两个表:

CREATE TABLE `x` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name_hash` char(32) NOT NULL,
  `access_time` bigint(20) unsigned NOT NULL,
  `name` varchar(1024) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_hash` (`name_hash`),
  KEY `access_time` (`access_time`),
  CONSTRAINT `x_ibfk_1` FOREIGN KEY (`access_time`) REFERENCES `update_time` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `y` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `x` bigint(20) unsigned NOT NULL,
  `update_time` bigint(20) unsigned NOT NULL,
  `reason` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `x` (`x`,`update_time`),
  KEY `reason` (`reason`),
  KEY `update_time` (`update_time`),
  CONSTRAINT `y_ibfk_1` FOREIGN KEY (`reason`) REFERENCES `reason` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `y_ibfk_2` FOREIGN KEY (`x`) REFERENCES `x` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `y_ibfk_3` FOREIGN KEY (`update_time`) REFERENCES `update_time` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

I used NetBeans to create the following JPA classes (X and Y are not the real names, think I did all of the required changes): 我使用NetBeans创建了以下JPA类(X和Y不是真实名称,以为我做了所有必需的更改):

@Entity
@Table(name = "X", catalog = "topiclymobile", schema = "", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"name_hash"})})
@NamedQueries({
    @NamedQuery(name = "X.findAll", query = "SELECT t FROM X t"),
    @NamedQuery(name = "X.findById", query = "SELECT t FROM X t WHERE t.id = :id"),
    @NamedQuery(name = "X.findByNameHash", query = "SELECT t FROM X t WHERE t.nameHash = :nameHash"),
    @NamedQuery(name = "X.findByName", query = "SELECT t FROM X t WHERE t.name = :name")})
public class X implements Serializable 
{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id", nullable = false)
    private Long id;

    @Basic(optional = false)
    @Column(name = "name_hash", nullable = false, length = 32)
    private String nameHash;

    @Basic(optional = false)
    @Column(name = "name", nullable = false, length = 1024)
    private String name;

    @JoinColumn(name = "access_time", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private UpdateTime accessTime;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "X")
    private List<Y> YList;

    public X() {
    }

    public X(Long id) {
        this.id = id;
    }

    public X(Long id, String nameHash, String name) {
        this.id = id;
        this.nameHash = nameHash;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNameHash() {
        return nameHash;
    }

    public void setNameHash(String nameHash) {
        this.nameHash = nameHash;
    }

    public String getName() {
        return name;
    }

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

    public UpdateTime getAccessTime() {
        return accessTime;
    }

    public void setAccessTime(UpdateTime accessTime) {
        this.accessTime = accessTime;
    }

    public List<Y> getYList() {
        return YList;
    }

    public void setYList(List<Y> YList) {
        this.YList = YList;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 89 * hash + (this.nameHash != null ? this.nameHash.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final X other = (X) obj;
        if ((this.nameHash == null) ? (other.nameHash != null) : !this.nameHash.equals(other.nameHash)) {
            return false;
        }
        return true;
    }
}
@Entity
@Table(name = "Y", catalog = "topiclymobile", schema = "", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"X", "update_time"})})
@NamedQueries({
    @NamedQuery(name = "Y.findAll", query = "SELECT t FROM Y t"),
    @NamedQuery(name = "Y.findById", query = "SELECT t FROM Y t WHERE t.id = :id")})
public class Y implements Serializable 
{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id", nullable = false)
    private Long id;

    @JoinColumn(name = "reason", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private Reason reason;

    @JoinColumn(name = "X", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private X X;

    @JoinColumn(name = "update_time", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private UpdateTime updateTime;

    public Y() {
    }

    public Y(Long id) {
        this.id = id;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Reason getReason() {
        return reason;
    }

    public void setReason(Reason reason) {
        this.reason = reason;
    }

    public X getX() {
        return X;
    }

    public void setX(X X) {
        this.X = X;
    }

    public UpdateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(UpdateTime updateTime) {
        this.updateTime = updateTime;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 13 * hash + (this.X != null ? this.X.hashCode() : 0);
        hash = 13 * hash + (this.updateTime != null ? this.updateTime.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Y other = (Y) obj;
        if (this.X != other.X && (this.X == null || !this.X.equals(other.X))) {
            return false;
        }
        if (this.updateTime != other.updateTime && (this.updateTime == null || !this.updateTime.equals(other.updateTime))) {
            return false;
        }
        return true;
    }
}

What I am after is all of the cases that "x" does not have a corresponding "y" for a given time (access_time and update_time are the same thing). 我所追求的是在所有情况下,“ x”在给定时间内没有对应的“ y”(access_time和update_time是同一件事)。

This SQL query works, I just cannot seem to translate it into an JPA query: 此SQL查询有效,我似乎无法将其转换为JPA查询:

SELECT t.id FROM x t LEFT JOIN y r ON t.id = r.x WHERE r.x IS NULL AND t.access_time = 1

It'd be helpful to see your entity classes to construct the actual query, but JPA does support LEFT JOIN s. 最好查看您的实体类来构造实际的查询,但是JPA确实支持LEFT JOIN This blog post has a full example, as does this question , but something like 这篇博客文章有一个完整的示例, 这个问题也有 ,但是类似

SELECT x FROM X x LEFT JOIN x.y ...

I'm not sure what the rest of the query should be as what you posted does not look like valid SQL (you have WHERE rx IS NULL , but the schema given defines x on table y as NOT NULL ; similarly, having WHERE rx IS NULL ought to make your left join match nothing, since t.id = rx would always evaluate to NULL ). 我不确定查询的其余部分应该是什么,因为您发布的内容看起来不像是有效的SQL(您拥有WHERE rx IS NULL ,但是给定的架构将表y上的x定义为NOT NULL ;类似地,拥有WHERE rx IS NULL应该使您的左t.id = rx匹配任何东西,因为t.id = rx总是计算为NULL )。

EDIT: I'm still confused as to how your sample SQL is a valid query, but something like this seems like it ought to translate into the SQL you provided: 编辑:关于您的示例SQL如何是一个有效的查询,我仍然感到困惑,但是类似这样的东西似乎应该转换为您提供的SQL:

SELECT x FROM X x LEFT JOIN x.yList y where y.x IS NULL and x.accessTime = :accessTime

Where the :accessTime parameter is the value of entityManager.getReference(UpdateTime.class, 1) . 其中:accessTime参数是entityManager.getReference(UpdateTime.class, 1) :accessTime entityManager.getReference(UpdateTime.class, 1)

Again, though, the FROM x LEFT JOIN y on x.id = yx WHERE yx IS NULL should match precisely no rows in Y, whereas (since it's a LEFT JOIN ), it will include all the rows in X. In other words, I think your query is equivalent to: 同样,尽管FROM x LEFT JOIN y on x.id = yx WHERE yx IS NULLFROM x LEFT JOIN y on x.id = yx WHERE yx IS NULL应该精确地匹配Y中的任何行,而(因为它是LEFT JOIN ),它将包括X中的所有行。换句话说,我认为您的查询等同于:

SELECT x.id FROM X where x.access_time = 1

Which would be this in JPA: 在JPA中是这样的:

SELECT x FROM X x where x.accessTime = :accessTime

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM