2010-05-12 203 views
0

鉴于以下两个表: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

这将会是有益的,看看你的实体类构建实际的查询,但JPA不支持LEFT JOIN小号。 This 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 
+0

更新的问题与班级 – TofuBeer 2010-05-12 00:42:45

+0

@TofuBeer:看我的更新。 – ig0774 2010-05-12 15:32:41

+0

SQL在mysql中工作......我承认我没有写它开始(数据库不是我的东西)。试试你发布的内容。 – TofuBeer 2010-05-12 18:08:16