JPA离开了联接查询

时间:2010-05-12 00:05:15

标签: jpa

鉴于以下两个表:

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;

我使用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;
    }
}

我所追求的是“x”在给定时间内没有相应的“y”的所有情况(access_time和update_time是相同的)。

这个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

1 个答案:

答案 0 :(得分:1)

查看实体类来构造实际查询会很有帮助,但JPA确实支持LEFT JOINThis blog post有一个完整的例子,this question就像

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

我不确定查询的其余部分应该是什么,因为您发布的内容看起来不像有效的SQL(您有WHERE r.x IS NULL,但是给定的模式将表y上的x定义为NOT NULL ;同样地,WHERE r.x IS NULL应该让你的左连接不匹配,因为t.id = r.x总是评估为NULL)。

编辑:我仍然对您的示例SQL如何成为有效查询感到困惑,但这样的事情似乎应该转换为您提供的SQL:

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

:accessTime参数是entityManager.getReference(UpdateTime.class, 1)的值。

然而,再次,FROM x LEFT JOIN y on x.id = y.x WHERE y.x IS NULL应该恰好与Y中没有行匹配,而(因为它是LEFT JOIN),它将包括X中的所有行。换句话说,我认为您的查询相当于:

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

JPA中会出现这种情况:

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