鉴于以下两个表:
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
答案 0 :(得分: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