使用JPA标准API筛选版本字段上的实体
我有一个具有嵌入id的实体,其中包含id和版本字段使用JPA标准API筛选版本字段上的实体,jpa,greatest-n-per-group,criteria-api,self-join,specification-pattern,Jpa,Greatest N Per Group,Criteria Api,Self Join,Specification Pattern,我有一个具有嵌入id的实体,其中包含id和版本字段 @Entity @Table(name = "MyEntity") public class MyEntity { @EmbeddedId private MyEntityEmbeddedId compositeId; @Column private DateTime begin; @Column private DateTime end; } @Embeddable public cla
@Entity
@Table(name = "MyEntity")
public class MyEntity {
@EmbeddedId
private MyEntityEmbeddedId compositeId;
@Column
private DateTime begin;
@Column
private DateTime end;
}
@Embeddable
public class MyEntityEmbeddedId {
@Column(name = "ID", nullable = false, updatable = false)
private Long id;
@Column(name = "VERSION", nullable = false, updatable = false)
private Long version;
public MyEntityEmbeddedId () {}
}
我需要用一些条件作为实体的过滤器来查询数据库。例如,我将请求一个日期和一个id列表
List<MyEntity> listEntities = getMyEntities(List<Long> ids, DateTime date);
如果以前的所有数据库记录都对应于筛选参数,我只需要获取这些记录,因为它们是对应id的版本号最高的记录:
+------+-----------+--------------------+
| id | version | began | end |
+------+-----------+--------------------+
| 1 | 3 | ... | ... |
| 2 | 2 | ... | ... |
+------+-----------+--------------------+
目前,我执行请求,但我在我的服务中的方法中过滤版本,但如果该版本已在数据库请求中过滤,则我更希望这样做。我不需要检索在筛选版本后将被丢弃的记录
我正在寻找一种使用JPA标准API进行自连接的方法
在下面的链接中,我想知道如何在JPA Criteria API中翻译建议的SQL,似乎接受的答案将解决我的问题
选择yt1*
从您的表yt1
左外联接表yt2
开启(yt1.id=yt2.id和yt1.rev
我的问题是当我试图创建联接时。您需要提供链接到联接中第二个实体的第一个实体的属性。由于我想进行自连接,所以实体中没有指向自身的属性
Join<MyEntity, MyEntity> selfJoin = root.join(MyEntity_.???);
Join selfJoin=root.Join(MyEntity);
如你所见,我使用的是MyEntity的静态元模型。有没有一种方法可以使用JPA标准API进行自连接
或者,也许有另一种方法来构建我的请求,而不是像另一个问题中建议的那样使用自左连接
我正在使用SpringDataJPA规范构建带有谓词的查询。然后使用findAll(规范)。我还有另外两个规范方法来为WithId()和withDate()生成谓词。这让我可以使用用户提供的“待定数量”参数创建查询
public static Specification<MyEntity> withIdAndDate(final List<Long> ids,
final DateTime date) {
return new Specification<MyEntity>() {
@Override
public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query,
CriteriaBuilder cb){
Join<MyEntity, MyEntity> selfJoin = root.join();
Predicate pIds = withIds(ids).toPredicate(root, query, cb);
Predicate pDate = withDate(date).toPredicate(root, query, cb);
return cb.and(pIds, pDate);
}
};
}
带有ID和日期的公共静态规范(最终列表ID,
最终日期(日期){
返回新规范(){
@凌驾
公共谓词toPredicate(根根、标准查询、,
标准生成器(cb){
Join selfJoin=root.Join();
谓词pIds=withIds(ids).toPredicate(根、查询、cb);
谓词pDate=withDate(date).toPredicate(root,query,cb);
返回cb.和(PID、pDate);
}
};
}
非常感谢您的帮助和建议 最后,我成功地找到了一种方法,使用JPA Criteria API将我的MyEntity过滤到最新版本,因此我将与您分享我的代码,希望它能帮助这里的人
public static Specification<MyEntity> withIdAndDate(final List<Long> ids,
final DateTime date) {
return new Specification<MyEntity>() {
@Override
public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query,
CriteriaBuilder cb){
Subquery<Long> subqueryVersion = query.subquery(Long.class);
Root<MyEntity> entity1 = subqueryVersion.from(MyEntity.class);
Expression<Long> expMaxVersion = cb.greatest(entity1
.get(MyEntity_.compositeId).get(MyEntityEmbeddedId_.version));
Expression<Long> expIdRoot = root.get(MyEntity_.compositeId)
.get(MyEntityEmbeddedId_.id);
Expression<Long> expIdEntity1 = entity1 .get(MyEntity_.compositeId)
.get(MyEntityEmbeddedId_.id);
Expression<Long> expVersionRoot = root.get(MyEntity_.compositeId)
.get(MyEntityEmbeddedId_.version);
Predicate pId = cb.equal(expIdRoot, expIdEntity1);
Predicate pIds = withIds(ids).toPredicate(entity1, query, cb);
Predicate pDate = withDate(date).toPredicate(entity1, query, cb);
subqueryVersion.select(expMaxVersion);
subqueryVersion.where(pId, pIds, pDate);
Predicate pQuery = cb.equal(expVersionRoot, subqueryVersion);
return cb.and(pQuery);
}
};
}
带有ID和日期的公共静态规范(最终列表ID,
最终日期(日期){
返回新规范(){
@凌驾
公共谓词toPredicate(根根、标准查询、,
标准生成器(cb){
Subquery subqueryVersion=query.Subquery(Long.class);
根entity1=子QueryVersion.from(MyEntity.class);
表达式expMaxVersion=cb.magest(entity1
.get(MyEntityEmbeddedId.version));
表达式expIdRoot=root.get(MyEntity_U2;.compositeId)
.get(MyEntityEmbeddedId\uUid);
表达式expIdEntity1=entity1.get(MyEntity\uuu.compositeId)
.get(MyEntityEmbeddedId\uUid);
表达式expVersionRoot=root.get(MyEntity_uuzy.compositeId)
.get(MyEntityEmbeddedId.version);
谓词pId=cb.equal(expIdRoot,expIdEntity1);
谓词pIds=withIds(ids).toPredicate(entity1,query,cb);
谓词pDate=withDate(date).toPredicate(entity1,query,cb);
subqueryVersion.select(expMaxVersion);
子查询版本,其中(pId、pId、pDate);
谓词pQuery=cb.equal(expVersionRoot,subqueryVersion);
返回cb.和(查询);
}
};
}
在下面的链接中,接受的答案帮助我在JPQL中构建查询,之后,我成功地将其转换为JPA Criteria API。我删除了查询的最后一部分,即“且不存在”部分。
public static Specification<MyEntity> withIdAndDate(final List<Long> ids,
final DateTime date) {
return new Specification<MyEntity>() {
@Override
public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query,
CriteriaBuilder cb){
Join<MyEntity, MyEntity> selfJoin = root.join();
Predicate pIds = withIds(ids).toPredicate(root, query, cb);
Predicate pDate = withDate(date).toPredicate(root, query, cb);
return cb.and(pIds, pDate);
}
};
}
public static Specification<MyEntity> withIdAndDate(final List<Long> ids,
final DateTime date) {
return new Specification<MyEntity>() {
@Override
public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query,
CriteriaBuilder cb){
Subquery<Long> subqueryVersion = query.subquery(Long.class);
Root<MyEntity> entity1 = subqueryVersion.from(MyEntity.class);
Expression<Long> expMaxVersion = cb.greatest(entity1
.get(MyEntity_.compositeId).get(MyEntityEmbeddedId_.version));
Expression<Long> expIdRoot = root.get(MyEntity_.compositeId)
.get(MyEntityEmbeddedId_.id);
Expression<Long> expIdEntity1 = entity1 .get(MyEntity_.compositeId)
.get(MyEntityEmbeddedId_.id);
Expression<Long> expVersionRoot = root.get(MyEntity_.compositeId)
.get(MyEntityEmbeddedId_.version);
Predicate pId = cb.equal(expIdRoot, expIdEntity1);
Predicate pIds = withIds(ids).toPredicate(entity1, query, cb);
Predicate pDate = withDate(date).toPredicate(entity1, query, cb);
subqueryVersion.select(expMaxVersion);
subqueryVersion.where(pId, pIds, pDate);
Predicate pQuery = cb.equal(expVersionRoot, subqueryVersion);
return cb.and(pQuery);
}
};
}