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
);

现在就可以了,尽管只有一个字段的查询大小让我感到害怕,但我认为给定的模型不会变得更简单。时间会证明这在实践中是否可用。