【问题标题】:Is it possible to make flexible order by in @Query?是否可以通过@Query 进行灵活排序?
【发布时间】:2019-06-25 09:51:20
【问题描述】:

我正在做一个项目(基本商店),目前我坚持订购(例如按价格、名称等)。我想知道是否有任何简单的方法可以针对我的商品使用 order by 对许多情况进行 1 次灵活查询。因为我的代码会返回无序列表的对象。

所以在这个项目中,我在用户在组合框元素中选择排序类型后向服务器发送请求。之后我的控制器选择排序方式,它调用查询,然后返回我们的对象。

请帮忙,有机会你能告诉我在控制器或服务实现中哪种方式的 switch(order_type) 更好?

附:如果我以 [http://localhost:9999/commodities/category-name/CPU/c.name%20asc] 控制器的身份向服务器发送请求,我会使用 switch 原因,只看到没有 .name asc 的 c,这就是我使用 switch 的原因。

代码:

控制器:

@RestController
@RequestMapping("commodities")
public class CommodityController {

@GetMapping("category-name/{name}/{order_type}")
    public ResponseEntity<List<CommodityDTO>> getCommodityByCategoryNameWithOrder(@PathVariable("name") String categoryName, @PathVariable("order_type") String order_type){
        List<CommodityDTO> byCategoryWithOrder;

        switch(order_type) {

        case "name_asc":
            byCategoryWithOrder = commodityService.getAllByCategoryNameWithOrder(categoryName, "c.name asc");
            break;

        case "name_desc":
            byCategoryWithOrder = commodityService.getAllByCategoryNameWithOrder(categoryName, "c.name desc");
            break;

        case "price_asc":
            byCategoryWithOrder = commodityService.getAllByCategoryNameWithOrder(categoryName, "c.price asc");
            break;

        case "price_desc":
            byCategoryWithOrder = commodityService.getAllByCategoryNameWithOrder(categoryName, "c.price desc");
            break;

        default:
            return null;
        }
        return new ResponseEntity<List<CommodityDTO>>(byCategoryWithOrder,HttpStatus.OK);
    }

服务实现:

@Service
@Transactional
public class CommodityServiceImpl implements CommodityService{

    @Autowired
    private CommodityRepository commodityRepository;

    @Autowired
    private ObjectMapperUtils objectMapperUtils;

    @Autowired
    private CloudinaryService cloudinaryService;

    @Override
    public List<CommodityDTO> getAllByCategoryNameWithOrder(String categoryName, String order_type){
            System.out.println("\n\n\n\nOrder type:\n"+order_type+"\n\n\n\n");
            return objectMapperUtils.mapAll(commodityRepository.findAllByCategoryNameWithOrder(categoryName, order_type), CommodityDTO.class);
        }

}

存储库:

    public interface CommodityRepository  extends JpaRepository<Commodity, Integer>{
    @Query("Select c FROM Commodity c "
                + "Join Category ct on c.category.id = ct.id "
                + "where ct.name = ?1 "
                + "order by ?2")
        List<Commodity> findAllByCategoryNameWithOrder(String categoryName, String order_type);
    }

【问题讨论】:

  • 首先,排序应该在前端而不是服务器端执行,因此您将保存数据库调用,即您只需将数据提供给前端并且排序应该在客户端完成,如果有一些逻辑变化或存在大量数据,那么排序数据然后在服务器端排序是好的,在这种情况下也可以获取数据并使用 java 逻辑来排序而不是 DB 逻辑跨度>
  • 不要编写自己的查询。只需添加findByCategoryName(String name, Pageable pageable)。在Pageable你可以指定你想要的尺寸和顺序。
  • @AyushGoyal 在客户端排序是否正确?因为如果我们模拟一种情况,例如我们有 1000 种不同价格的产品,而我们使用页面仅请求 20 种产品(这始终是更好的用户体验所必需的),根据您的建议,我们将仅在 20 种范围内进行排序我们从第一次获取请求中获得的元素。因此,如果我们按价格排序,我们实际上不会得到最贵的一个,或者是我们商店中最便宜的,而是我们从页面请求中获得的 20 个对象中的一个。为了避免这种情况,我们需要使用 order by 或 SortedSet 集合发出请求。
  • @Yurii Malskiy 正确,我的错!!

标签: java spring jpa spring-data-jpa spring-data


【解决方案1】:

您应该考虑将 QueryDSL 扩展用于 Spring 数据。这与 Spring Data Web 扩展相结合,将允许您通过任何属性组合过滤实体并应用排序和分页无需编写任何代码。

将以下内容添加到您的配置中,您的代码将如下所示:

@EnableSpringDataWebSupport

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.extensions.querydsl

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web.type-safe

请参阅此处了解如何设置您的项目以支持 QueryDsl:

https://www.baeldung.com/querydsl-with-jpa-tutorial

控制器

@GetMapping("/searchCommodities")
public ResponseEntity<List<CommodityDTO>> findCommodities(
         @QuerydslPredicate(root = Commodity.class) Predicate predicate,Pageable pageable){

     return new ResponseEntity<List<CommodityDTO>> 
                (commodityService.getCategories(predicate, pageable), HttpStatus.OK);
}

服务

public class CommodityServiceImpl implements CommodityService{
    @Override
    public List<CommodityDTO> getCategories(Predicate predicate, Pageable pageable){
        return objectMapperUtils.mapAll(commodityRepository.findAll(
                       predicate, pageable), CommodityDTO.class);
}

存储库

public interface CommodityRepository  extends JpaRepository<Commodity, Integer>, 
                     QueryDslPredicateExecutor<Commodity>{
    //no query methods required
}

您现在可以调用,例如:

/searchCommodities?name=someName&sort=someProperty

/searchCommodities?name=someName&someOtherproperty=xyz&sort=someProperty,desc&sort=someProperty,asc

/searchCommodities?name=x&name=y&name=z //name = x or y or z

【讨论】:

    【解决方案2】:

    有两种选择:

    1. 如果您想编写自己的查询,请改用 jOOQ。
    2. 使用 Spring Data 查询方法并作为附加参数传递 Sort 对象。

    【讨论】:

    • 谢谢,在您回复前几分钟找到了该选项。猜猜这对我的解决方案来说是完美的。 :)
    猜你喜欢
    • 1970-01-01
    • 2013-05-14
    • 2012-02-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-27
    • 2015-02-16
    相关资源
    最近更新 更多