如何对 Spring 数据中的 case 语句的结果进行排序?
How can I sort on the results of a case statement in Spring Data?
我们有一个 UI sortable table 由以下查询支持,单击列会 order by
在该列上升序或降序。问题是其中一列根据条件呈现用户角色名称或他们的人名,我们需要能够对该列进行排序。
目前这是存储库定义
Page<UserActivityLog> findByActivityTargetUserId( Long id, Pageable pageable );
我正在尝试编写一个看起来或多或少像这样的规范。
private static class UserSpecification implements Specification<UserActivityLog> {
@Override
public Predicate toPredicate(
final Root<UserRelatedEntity> root,
final CriteriaQuery<?> query,
final CriteriaBuilder cb )
cb.selectCase()
.when( root.<Boolean>get( "user.setting.fieldBoolean" ),
root.<RoleType>get( "user.role.roleTypeEnum" ).toString() )
.otherwise( root.<String>get("user.humanNameString") )
... //magic
这显然是不完整的。我不确定如何接受它(假设它适合我想做的案例陈述)并使其 return 成为 Predicate
。我什至可能无法使用 Specification
添加 case 语句,尽管我怀疑我可以。我也不确定一旦我让它工作,我将如何将 "field name" 传递给 Sort
(我知道如何传递字段名称,我想我只是不确定如何弄清楚字段名称是什么)。
值得一提的是,我还没有真正理解 CriteriaBuilder
api。
Update 我从 an oracle tutorial 中抓取的 case 语句的稍微修改的示例,它演示了我需要做什么,我不需要结果不过,我的 return 对象中的大小写列。
SQL> select job, ename
2 , case
3 when msal <= 2500
4 then 'cheap'
5 else 'expensive'
6 end as class
7 from employees
8 where bdate < date '1964-01-01'
9 order by class;
如何在仍然使用 Spring 数据存储库的同时根据案例语句生成的字段对我的结果进行排序?
您可以使用 Jpa Meta Model 它会对 Specifications
有很大帮助,我不确定我是否理解您的意思,但这里有一个示例可能会有所帮助。
public abstract class ASpecifications{
// filtering by Option 1
public static Specification<A> findByOption1(final String opt1) {
return new Specification<A>() {
@Override
public Predicate toPredicate(Root<A> root,
CriteriaQuery<?> arg1, CriteriaBuilder cb) {
return cb.equal(root.get(A_.op1), prop);
}
};
}
// filtering by option 2
public static Specification<A> findByOption2(final String opt2) {
return new Specification<A>() {
@Override
public Predicate toPredicate(Root<A> root,
CriteriaQuery<?> arg1, CriteriaBuilder cb) {
return cb.equal(root.get(A_.opt2), prop);
}
};
}
}
您可以这样定义 Pageable :
PageRequest request = new PageRequest(pageNumber - 1, PAGE_SIZE, Sort.Direction.DESC,"optionTOSort");
并将其传递给您的服务class
import static ASpecifications.*;
import static org.springframework.data.jpa.domain.Specifications.*;
public class YourService {
// autowire repository
public Page<A> filter(String opt1,String opt2,Pageable pageable){
Specifications<A> spec = null;
if(opt1!=null){
spec = where(findByOption1(opt1));
}
if(opt2!=null){
spec spec == null ? where(findByOption2(opt2)) : spec.and (findByOption2(opt2));
}
repository.findAll(spec,pageabl);
}
}
这就是我最后做的。我需要一次获取每个属性(恕我直言,教程并不明显),然后在最后为了 return 一个谓词,我创建了另一个规范,我委托给它具有实际的 where 子句(在这种情况下一个简单的 id)。值得一提的是,.Index.NAME
这东西只是一个包含属性名称的静态字符串,我们还没有决定是否生成元模型。
public class FilterByIdForUserSpecification<AL extends AbstractActivityLogWithSiteUser> implements Specification<AL>
{
private final Sort.Direction direction;
private final Specification<AL> specification;
public FilterByIdForUserSpecification(
final Specification<AL> specification,
final Sort.Direction direction )
{
this.specification = specification;
this.direction = direction;
}
@Override
public Predicate toPredicate(
final Root<AL> root,
final CriteriaQuery<?> query,
final CriteriaBuilder cb )
{
Path<Object> siteUser = root.get( AbstractActivityLogWithSiteUser.Index.USER );
Path<Object> ownerOrg = siteUser.get( SiteUser.Index.PRI_ORG ).get( Organization.Index.OWNER );
Path<Object> fullName = siteUser.get( SiteUser.Index.CONTACT ).get( Contact.Index.FULL_NAME );
Path<Object> roleDisp = siteUser.get( SiteUser.Index.ROLE ).get( Role.Index.DISPLAY );
Expression<Object> queryCase = cb.selectCase()
.when( cb.equal( ownerOrg, true ), roleDisp )
.otherwise( fullName );
query.orderBy( direction( cb, queryCase, direction ) );
return specification.toPredicate( root, query, cb );
}
static Order direction( final CriteriaBuilder cb, final Expression<?> e, final Sort.Direction direction )
{
if ( direction == Direction.ASC )
{
return cb.asc( e );
}
return cb.desc( e );
}
}
我们有一个 UI sortable table 由以下查询支持,单击列会 order by
在该列上升序或降序。问题是其中一列根据条件呈现用户角色名称或他们的人名,我们需要能够对该列进行排序。
目前这是存储库定义
Page<UserActivityLog> findByActivityTargetUserId( Long id, Pageable pageable );
我正在尝试编写一个看起来或多或少像这样的规范。
private static class UserSpecification implements Specification<UserActivityLog> {
@Override
public Predicate toPredicate(
final Root<UserRelatedEntity> root,
final CriteriaQuery<?> query,
final CriteriaBuilder cb )
cb.selectCase()
.when( root.<Boolean>get( "user.setting.fieldBoolean" ),
root.<RoleType>get( "user.role.roleTypeEnum" ).toString() )
.otherwise( root.<String>get("user.humanNameString") )
... //magic
这显然是不完整的。我不确定如何接受它(假设它适合我想做的案例陈述)并使其 return 成为 Predicate
。我什至可能无法使用 Specification
添加 case 语句,尽管我怀疑我可以。我也不确定一旦我让它工作,我将如何将 "field name" 传递给 Sort
(我知道如何传递字段名称,我想我只是不确定如何弄清楚字段名称是什么)。
值得一提的是,我还没有真正理解 CriteriaBuilder
api。
Update 我从 an oracle tutorial 中抓取的 case 语句的稍微修改的示例,它演示了我需要做什么,我不需要结果不过,我的 return 对象中的大小写列。
SQL> select job, ename
2 , case
3 when msal <= 2500
4 then 'cheap'
5 else 'expensive'
6 end as class
7 from employees
8 where bdate < date '1964-01-01'
9 order by class;
如何在仍然使用 Spring 数据存储库的同时根据案例语句生成的字段对我的结果进行排序?
您可以使用 Jpa Meta Model 它会对 Specifications
有很大帮助,我不确定我是否理解您的意思,但这里有一个示例可能会有所帮助。
public abstract class ASpecifications{
// filtering by Option 1
public static Specification<A> findByOption1(final String opt1) {
return new Specification<A>() {
@Override
public Predicate toPredicate(Root<A> root,
CriteriaQuery<?> arg1, CriteriaBuilder cb) {
return cb.equal(root.get(A_.op1), prop);
}
};
}
// filtering by option 2
public static Specification<A> findByOption2(final String opt2) {
return new Specification<A>() {
@Override
public Predicate toPredicate(Root<A> root,
CriteriaQuery<?> arg1, CriteriaBuilder cb) {
return cb.equal(root.get(A_.opt2), prop);
}
};
}
}
您可以这样定义 Pageable :
PageRequest request = new PageRequest(pageNumber - 1, PAGE_SIZE, Sort.Direction.DESC,"optionTOSort");
并将其传递给您的服务class
import static ASpecifications.*;
import static org.springframework.data.jpa.domain.Specifications.*;
public class YourService {
// autowire repository
public Page<A> filter(String opt1,String opt2,Pageable pageable){
Specifications<A> spec = null;
if(opt1!=null){
spec = where(findByOption1(opt1));
}
if(opt2!=null){
spec spec == null ? where(findByOption2(opt2)) : spec.and (findByOption2(opt2));
}
repository.findAll(spec,pageabl);
}
}
这就是我最后做的。我需要一次获取每个属性(恕我直言,教程并不明显),然后在最后为了 return 一个谓词,我创建了另一个规范,我委托给它具有实际的 where 子句(在这种情况下一个简单的 id)。值得一提的是,.Index.NAME
这东西只是一个包含属性名称的静态字符串,我们还没有决定是否生成元模型。
public class FilterByIdForUserSpecification<AL extends AbstractActivityLogWithSiteUser> implements Specification<AL>
{
private final Sort.Direction direction;
private final Specification<AL> specification;
public FilterByIdForUserSpecification(
final Specification<AL> specification,
final Sort.Direction direction )
{
this.specification = specification;
this.direction = direction;
}
@Override
public Predicate toPredicate(
final Root<AL> root,
final CriteriaQuery<?> query,
final CriteriaBuilder cb )
{
Path<Object> siteUser = root.get( AbstractActivityLogWithSiteUser.Index.USER );
Path<Object> ownerOrg = siteUser.get( SiteUser.Index.PRI_ORG ).get( Organization.Index.OWNER );
Path<Object> fullName = siteUser.get( SiteUser.Index.CONTACT ).get( Contact.Index.FULL_NAME );
Path<Object> roleDisp = siteUser.get( SiteUser.Index.ROLE ).get( Role.Index.DISPLAY );
Expression<Object> queryCase = cb.selectCase()
.when( cb.equal( ownerOrg, true ), roleDisp )
.otherwise( fullName );
query.orderBy( direction( cb, queryCase, direction ) );
return specification.toPredicate( root, query, cb );
}
static Order direction( final CriteriaBuilder cb, final Expression<?> e, final Sort.Direction direction )
{
if ( direction == Direction.ASC )
{
return cb.asc( e );
}
return cb.desc( e );
}
}