我需要对以下场景进行建模:实体具有值,可以随时间变化,我需要保留所有历史值.例如,我有实体文章,有标题.如果文章是在2015年1月1日创建的,它将获得标题“标题1”,然后,在2015年2月1日,某人将标题更改为“标题2”,并且在3月1日,标题更改为“标题3”.我想问一下“2015年2月20日这篇文章的标题是什么?”
为此,我创建了具有标题列表的Article实体:
@Entity
public class Article {
@Id
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List title = new LinkedList<>();
//Setters and getters are here
}
标题看起来像这样:
@Entity
public class Title extends DateDependentEntity
{@NotNull
private String title;
}
和DateDependentEntity看起来像这样(我有很多)
@MappedSuperclass
public abstract class DateDependentEntity {
@Id
private Long id;
@Column(nullable = false)
private LocalDate validFrom;
@ManyToOne
private PARENT parent;
}
一切正常,我已经创建了保存和阅读这些实体的方法(比如“给我一篇文章,其中id = 1,其值有效于20.2.2015”).
但我有问题找出依赖于日期的HQL过滤器查询,例如“给我所有在’20.2.2015”上标题包含’dog’的文章.”
首先,我会使用这样的东西:
SELECT DISTINCT a FROM Article a JOIN a.title at WITH (at.validFrom <= :date) WHERE at.title LIKE :title
但这并不总是能够带来预期的结果 – 如果标题是1月份的“我们爱狗”和“我们喜欢猫”自2月以来我过滤了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
);
现在这样做,虽然只有一种字段的查询大小让我感到害怕,但我认为给定的模型不会变得简单得多.时间将证明这是否可以在实践中使用.