如何将单个JPA规范类和方法用于多个实体

问题描述 投票:0回答:2

我正在创建一个具有诸如Product,Category,Mechanical,UsageLocation等实体的Spring Boot应用程序。所有这些实体的共同点是它们都具有一个名为name的String属性,并且可以使用name从UI进行过滤。我已经写了一个使用名称过滤产品的规范,它正在起作用。下面是代码

public final class ProductSpecifications 
{

    public static Specification<Product> whereNameContains(String name)
    {
        Specification<Product> finalSpec = (Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb)
            -> cb.like(root.get(Product_.PRODUCT_NAME), "%"+name+"%");
        return finalSpec;
    }

    public static Specification<Product> whereNameEqauls(String name)
    {
        Specification<Product> finalSpec = (Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb)
            -> cb.equal(root.get(Product_.PRODUCT_NAME), name);
        return finalSpec;
    }
}

现在的问题是,我不得不再次编写相同的代码来过滤其他实体,唯一的区别是类名(产品),字段名(PRODUCT_NAME)和方法的返回类型。我可以创建一个通用的类和方法,将类名和字段名作为参数传递给它,并返回各自返回类型的说明。

java spring spring-data-jpa criteria-api
2个回答
1
投票
首先让您的SpecificationsBuilder通用

@Service public final class SpecificationsBuilder<T> { public static Specification<T> whereNameContains(String key,String name) { Specification<T> finalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> cb.like(root.get(key), "%"+name+"%"); return finalSpec; } }

然后进入控制器@Autowire SpecificationsBuilder

@Autowire private final SpecificationBuilder<Product> specificationBuilder; public List<Product> getAll(String name) { Specification<Product> specification = specificationBuilder.whereNameContains(Product_.PRODUCT_NAME, name); List<Product> products = productRepo.findAll(specification);// pass the specifications return products; }

您可以为SpecificationBuilder创建自己的通用库,我有一个。您可以找到详细信息here

0
投票
我能够使用Abinash的答案解决此问题。以下是可重用规范类的工作代码

import java.util.List; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import com.ec.application.model.Product; import com.ec.common.Filters.FilterAttributeData; import com.ec.common.Filters.FilterDataList; public class SpecificationsBuilder<T> { //#######################################/#################// // Level 0 - If the field that you want to query is parent entity // //########################################################// public Specification<T> whereDirectFieldContains(String key,List<String> names) { Specification<T> finalSpec = null; for(String name:names) { Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> cb.like(root.get(key), "%"+ name +"%"); finalSpec = specOrCondition(finalSpec,internalSpec); // to append specifications as I am filtering based on list of strings } return finalSpec; } //#######################################// // Level 1 - If you want to query a child entity. // // //#######################################// public Specification<T> whereChildFieldContains(String childTable, String childFiledName, List<String> names) { Specification<T> finalSpec = null; for(String name:names) { Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> cb.like(root.get(childTable).get(childFiledName), "%"+ name +"%"); finalSpec = specOrCondition(finalSpec,internalSpec); // to append specifications as I am filtering based on list of strings } return finalSpec; } //#######################################// // Reusable Spec Setter to handle NULLs. // //#######################################// public Specification<T> specAndCondition(Specification<T> finalSpec, Specification<T> internalSpec) { if(finalSpec == null) return internalSpec; else return finalSpec.and(internalSpec); } public Specification<T> specOrCondition(Specification<T> finalSpec, Specification<T> internalSpec) { if(finalSpec == null) return internalSpec; else return finalSpec.or(internalSpec); } }

这是实体规范类的代码

public static Specification<Product> getSpecification(FilterDataList filterDataList) { List<String> productNames = specbldr.fetchValueFromFilterList(filterDataList,"product"); List<String> categoryNames = specbldr.fetchValueFromFilterList(filterDataList,"category"); Specification<Product> finalSpec = null; if(productNames != null && productNames.size()>0) finalSpec = specbldr.specAndCondition(finalSpec, specbldr.whereDirectFieldContains(Product_.PRODUCT_NAME, productNames)); if(categoryNames != null && categoryNames.size()>0) { finalSpec = specbldr.specAndCondition(finalSpec, specbldr.whereChildFieldContains(Product_.CATEGORY,Category_.CATEGORY_NAME, categoryNames)); } return finalSpec; }

© www.soinside.com 2019 - 2024. All rights reserved.