jpaspecification适用于字符串,但日期和联接字段有问题

fcwjkofz  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(389)

我正在努力扩展这个baeldung教程https://www.baeldung.com/rest-api-search-language-spring-data-specifications
但是我希望规范是通用的,并且我希望允许客户端通过嵌入对象的值进行搜索。一切都适用于字符串和一些数字,但不适用于ID和其他更复杂的对象,如 Date .
我的模型:(假设一个人只能养一只宠物)

@Entity
public Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private ID id;
    private String name;
    private Date dateOfBirth
    private Integer age;
    private Pet pet;
    // Getter & Setters etc
}

@Entity
public Pet {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private ID id;
    private String type;
    private String name;
    private Integer numOfLegs;
    // Getter & Setters etc
}

人员存储库:

@Repository
public interface PersonRepository extends JpaRepository<Person, Integer>, JpaSpecificationExecutor<Person>{}

搜索条件,将保存键,运算符和值,我们可以搜索。

public class EntitySearchCriteria {
    private String key;
    private String operation;
    private Object value;

    public EntitySearchCriteria(final String key, final String operation, final Object value) {
        this.key = key;
        this.operation = operation;
        this.value = value;
    }  
    // Getters and Setters etc

我的泛型规范类(这里的操作实际上是构建要使用的 predicate )。这还允许客户机对联接表的值设置搜索条件。e、 g.“pet.name=松饼”

public abstract class AbstractEntitySpecification<T, ID extends Serializable> implements Specification<T> {

    protected EntitySearchCriteria criteria;

    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        if (criteria.getOperation().equalsIgnoreCase(">")) {
            return criteriaBuilder.greaterThanOrEqualTo(root.<String>get(criteria.getKey()), criteria.getValue().toString());
        } else if (criteria.getOperation().equalsIgnoreCase("<")) {
            return criteriaBuilder.lessThanOrEqualTo(root.<String>get(criteria.getKey()), criteria.getValue().toString());
        } else if (criteria.getOperation().equalsIgnoreCase(":")) {
            if (criteria.getKey().contains(".")) {
                String[] joinCriteriaArray = criteria.getKey().split("\\.");
                Class<?> joinedClass = root.get(joinCriteriaArray[0]).getClass();
                Join<T, ?> joinedRelationship = root.join(joinCriteriaArray[0]);
                return criteriaBuilder.equal(joinedRelationship.get(joinCriteriaArray[1]), criteria.getValue());
            }
            if (root.get(criteria.getKey()).getJavaType() == String.class) {
                return criteriaBuilder.like(root.<String>get(criteria.getKey()), "%" + criteria.getValue() + "%");
            } else {
                return criteriaBuilder.equal(root.get(criteria.getKey()), criteria.getValue());
            }
        }
        return null;
    }
}

我希望允许这种查询的任何实体只需要有 AbstractEntitySpecification ```
public class PersonSpecification extends AbstractEntitySpecification<Person, Integer> {
public PersonSpecification (final EntitySearchCriteria entitySearchCriteria) {
this.criteria = entitySearchCriteria;
}
}

这些是我做的测试。对person的字符串或int属性(即person.name、person.age)的任何搜索都将起作用,但对dateofbirth的搜索将不起作用。任何对pet的属性(字符串)的搜索都可以使用join,但是对id(整数)的搜索都不行,不管我是将id作为int还是字符串传递。每次考试我都会把这种行为写进评语里。

public class PersonSpecificationMediumTest extends AbstractMediumTest {
@Autowired
private PersonRepository personRepository;

@Autowired
private PetRepository petRepository;

Person person1;
Person person2;

@Before
public void setUp() {
    Pet muffins = new Pet(1, "cat", "muffins", 4);
    Pet rex= new Pet(2, "dog", "rex", 4);
    petRepository.saveAll(Arrays.asList(muffins , rex));

    person1 = new Person();
    person1.setName("David");
    person1.setDateOfBirth(Date.parse("1979-03-01");
    person1.setPet(muffins);
    person1 = personRepository.saveAndFlush(person1);

    person2 = new Person();
    person2.setName("Mary");
    person2.setDateOfBirth(Date.parse("1982-03-01");
    person2.setPet(rex);
    person2 = personRepository.saveAndFlush(person2);
}

@Test //Works
public void toPredicate_findByNameEquals_assertCorrectResult() {
    PersonSpecification spec
            = new PersonSpecification(new EntitySearchCriteria("name", ":", "David"));

    List<Person> results = personRepository.findAll(spec);

    Assert.assertEquals(person1, results.get(0));
}

@Test // Works
public void toPredicate_findByPetNameEquals_assertCorrectResult() {
   PersonSpecification spec
            = new PersonSpecification(new EntitySearchCriteria("client.name", ":", "Rex"));

    List<Person> results = personRepository.findAll(spec);

     Assert.assertEquals(person2, results.get(0));
}

@Test // Return empty list. Cannot find the pet by Id.
public void toPredicate_findByPetIdEquals_assertCorrectResult() {
     PersonSpecification spec
            = new PersonSpecification(new EntitySearchCriteria("pet.id", ":", 2));

     List<Person> results = personRepository.findAll(spec);

     Assert.assertEquals(person2, results.get(0));
}

@Test // org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [2] did not match expected type [java.lang.Integer (n/a)];
public void toPredicate_findByPetIdAsStringEquals_assertCorrectResult() {
     PersonSpecification spec
            = new PersonSpecification(new EntitySearchCriteria("pet.id", ":", "2"));

     List<Person> results = personRepository.findAll(spec);

     Assert.assertEquals(person2, results.get(0));
}

@Test // Fails on org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [2020-01-01] did not match expected type [java.util.Date (n/a)]
public void toPredicate_findByDateOfBirthBetween_assertCorrectResult() {
    PersonSpecification spec1
            = new PersonSpecification(new EntitySearchCriteria("dateOfBirth", "<", "1990-01-01"));
    PersonSpecification spec2
            = new PersonSpecification(new EntitySearchCriteria("dateOfBirth", ">", "1970-01-01"));

    List<Person> results = personRepository.findAll(spec1.and(spec2));

    Assert.assertTrue(results.size() == 2);
}

}

你知道为什么约会这么麻烦吗?我想用照片上的日期 `greaterThanOrEqualTo` 以及 `lessThanOrEqualTo` ,但传入criteria.getvalue(object)会产生编译错误,因此它会强制我使用对象的字符串表示形式。但显示的错误是 `org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [2020-01-01] did not match expected type [java.util.Date (n/a)]` 这向我表明它不能将字符串与日期进行比较,这是有意义的,但是为什么要阻止我传递date对象呢?
另外,为什么在联接表中id是这样一个问题?为什么找不到 `id = 2` ,我会认为这是直截了当的,特别是因为我可以成功地通过宠物的腿数来搜索。它一定与id是可序列化的有关。
6rqinv9w

6rqinv9w1#

查看javadoc Date.parse . 基本的部分已经与宣言一起:
@已弃用
公共静态长解析(字符串s)
正如它明确指出的,它返回一个 long 价值观。得到一个 Date 可以使用的对象 SimpleDateFormat 继承的 DateFormat.parse(String s) ,例如:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = sdf.parse("1979-03-01");

相关问题