JOIN ... WITH 子句中不存在限制的替代解决方案
Alternative solution to nonexisting limit in JOIN ... WITH clause
我需要对以下场景进行建模:实体有值,可以随时间变化,我需要保留所有历史值。例如,我有实体文章,它有标题。如果文章是在 2015 年 1 月 1 日创建的,它将获得标题 "Title 1",然后,在 2015 年 2 月 1 日有人将标题更改为 "Title 2",并在 3 月 1 日将标题更改为 "Title 3"。我想问 "What was the article's title on 20th February 2015?"
为此,我创建了具有标题列表的文章实体:
@Entity
public class Article {
@Id
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<ArticleTitle> title = new LinkedList<>();
//Setters and getters are here
}
标题看起来像这样:
@Entity
public class Title extends DateDependentEntity<Title> {
@NotNull
private String title;
}
DateDependentEntity 看起来像这样(我有很多)
@MappedSuperclass
public abstract class DateDependentEntity<PARENT> {
@Id
private Long id;
@Column(nullable = false)
private LocalDate validFrom;
@ManyToOne
private PARENT parent;
}
一切正常,我已经创建了保存和读取这些实体的方法(如 "give me article where id = 1 with values valid on 20. 2. 2015")。
但是我在计算依赖于日期的 HQL 过滤器查询时遇到问题,例如 "Give me all articles that had title containing 'dog' on '20. 2. 2015'"。
首先,我会使用这样的东西:
SELECT DISTINCT a FROM Article a JOIN a.title at WITH (at.validFrom <= :date) WHERE at.title LIKE :title
但这并不总是 return 预期结果 - 如果标题在 1 月份是 "We love dogs" 并且从 2 月份开始是 "We like cats" 并且我在 3 月份过滤了包含狗的值,它仍然会找到这篇文章。据我所知,我不能在 WITH 子句中使用某种限制,对吗?
所以我虽然会使用子查询,但在 HQL 中不支持 LIMIT,所以问题与上面的 JOIN 相同。
是否有一些 HQL 查询可以解决我的问题,或者我的模型完全错误?
在整天摆弄 HQL 之后(并且在意识到 IntelliJ 将我的查询标记为语法错误后,尽管查询有效),我想到了这个:
SELECT at.parent FROM ArticleTitle at
WHERE at.title LIKE :title AND (at.validFrom, at.parent) IN (
SELECT max(at2.validFrom), at2.parent FROM ArticleTitle at2
WHERE at2.validFrom <= :date GROUP BY at2.parent
);
现在就可以了,尽管只有一个字段的查询大小让我感到害怕,但我认为给定的模型不会变得更简单。时间会证明这在实践中是否可用。
我需要对以下场景进行建模:实体有值,可以随时间变化,我需要保留所有历史值。例如,我有实体文章,它有标题。如果文章是在 2015 年 1 月 1 日创建的,它将获得标题 "Title 1",然后,在 2015 年 2 月 1 日有人将标题更改为 "Title 2",并在 3 月 1 日将标题更改为 "Title 3"。我想问 "What was the article's title on 20th February 2015?"
为此,我创建了具有标题列表的文章实体:
@Entity
public class Article {
@Id
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<ArticleTitle> title = new LinkedList<>();
//Setters and getters are here
}
标题看起来像这样:
@Entity
public class Title extends DateDependentEntity<Title> {
@NotNull
private String title;
}
DateDependentEntity 看起来像这样(我有很多)
@MappedSuperclass
public abstract class DateDependentEntity<PARENT> {
@Id
private Long id;
@Column(nullable = false)
private LocalDate validFrom;
@ManyToOne
private PARENT parent;
}
一切正常,我已经创建了保存和读取这些实体的方法(如 "give me article where id = 1 with values valid on 20. 2. 2015")。
但是我在计算依赖于日期的 HQL 过滤器查询时遇到问题,例如 "Give me all articles that had title containing 'dog' on '20. 2. 2015'"。
首先,我会使用这样的东西:
SELECT DISTINCT a FROM Article a JOIN a.title at WITH (at.validFrom <= :date) WHERE at.title LIKE :title
但这并不总是 return 预期结果 - 如果标题在 1 月份是 "We love dogs" 并且从 2 月份开始是 "We like cats" 并且我在 3 月份过滤了包含狗的值,它仍然会找到这篇文章。据我所知,我不能在 WITH 子句中使用某种限制,对吗?
所以我虽然会使用子查询,但在 HQL 中不支持 LIMIT,所以问题与上面的 JOIN 相同。
是否有一些 HQL 查询可以解决我的问题,或者我的模型完全错误?
在整天摆弄 HQL 之后(并且在意识到 IntelliJ 将我的查询标记为语法错误后,尽管查询有效),我想到了这个:
SELECT at.parent FROM ArticleTitle at
WHERE at.title LIKE :title AND (at.validFrom, at.parent) IN (
SELECT max(at2.validFrom), at2.parent FROM ArticleTitle at2
WHERE at2.validFrom <= :date GROUP BY at2.parent
);
现在就可以了,尽管只有一个字段的查询大小让我感到害怕,但我认为给定的模型不会变得更简单。时间会证明这在实践中是否可用。