【问题标题】:How can I sort on the results of a case statement in Spring Data?如何对 Spring Data 中的 case 语句的结果进行排序?
【发布时间】:2015-07-26 17:50:33
【问题描述】:

我们有一个由以下查询支持的 UI 可排序表,单击列会在该列上执行 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 

这显然是不完整的。我不确定如何接受这个(假设它适合我想要做的案例陈述)并让它返回Predicate。我什至可能无法使用Specification 添加案例陈述,尽管我怀疑我可以。我也不确定一旦我让它工作,我将如何将“字段名称”传递给Sort(我知道如何传递字段名称,我想我只是不确定如何弄清楚字段名称是什么)。

值得一提的是,我还不太了解CriteriaBuilder api。

更新我从an oracle tutorial 中抓取的一个案例语句的稍微修改的示例,它演示了我需要做什么,我不需要在我的回报中使用 case-ed 列的结果对象。

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 Data 存储库的同时根据 case 语句生成的字段对结果进行排序?

【问题讨论】:

    标签: java jpa-2.0 spring-data spring-data-jpa criteria-api


    【解决方案1】:

    这就是我最终要做的。我需要一次获取每个属性(教程恕我直言不明显),然后最后为了返回一个谓词,我创建了另一个规范,我委托给它具有实际的 where 子句(在这种情况下是一个简单的 by 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 );
    }
    }
    

    【讨论】:

    • 投票,拯救我的一天。
    • 正是我所需要的......让我免于切换到 jpql :)
    【解决方案2】:

    您可以使用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");
    

    并将其传递给您的服务类

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

    【讨论】:

    • 我试图用一个 sql 示例来澄清这个问题,以便您更好地理解我想要做什么。我确信这样做是可能的,因为 jpql 和标准构建器都支持案例陈述,这只是找到正确的咒语
    猜你喜欢
    • 1970-01-01
    • 2016-12-27
    • 2012-01-06
    • 2016-02-10
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 2019-05-22
    • 2014-09-14
    相关资源
    最近更新 更多