[英]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 NULL
的FROM 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.