转载

Spring Data JPA 定义查询方法:创建方法详解和属性表达式

1、Spring Data JPA 中创建数据库查询方法的具体操作说明。方法中的SQL关键词和方法中的数据设置。

2、Spring Data JPA 中对属性字段的解析方式是什么样子的?属性表达式怎么介绍?

三、查询方法的创建

内部基础架构中有个根据方法名的查询生成器机制,对于在存储库的实体上构建约束查询很有用。

该机制方法的前缀有find…By、read…By、query…By、count…By和get…By,从这些方法可以分析它的其余部分(实体里面的字段)。

引入子句可以包含其他表达式,例如在Distinct要创建的查询上设置不同的标志。

然而,第一个By作为分隔符来指示实际标准的开始。在一个非常基本的水平上,你可以定义实体性条件,并与它们串联(And和Or)。

用一句话概括,待查询功能的方法名由查询策略(关键字)、查询字段和一些限制性条件组成。在如下例子中,可以直接在controller里面进行调用以查看效果:

interface PersonRepository extends Repository<User, Long> {
// and的查询关系
List<User> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
//包含distinct去重、or的SQL语法
List<User> findDistinctPeopleByLastnameOrFirstname(Stringlastname, String firstname);
List<User> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
//根据lastname字段查询忽略大小写
List<User> findByLastnamelgnoreCase(String lastname);
//根据lastname和firstname查询equal并且忽略大小写
List<User> findByLastnameAndFirstnameAllIgnoreCase(Stringlastname, String firstname);
//对查询结果根据lastname排序
List<User> findByLastnameOrderByFirstnameAsc(String lastname);
List<User> findByLastnameOrderByFirstnameDesc(String lastname);
}

解析方法的实际结果取决于创建查询的持久性存储。但是,有一些常见的事项需要注意:

  1. 表达式通常是可以连接的运算符的属性遍历。你可以使用组合属性表达式AND和OR。你还可以将运算关键字Between、LessThan、GreaterThan、Like作为属性表达式。受支持的操作员可能因数据存储而异,因此请参阅官方参考文档的相应部分内容。
  2. 该方法解析器支持设置一个IgnoreCase标志个别特性(例如,findByLastnameIgnoreCase(…))或支持忽略大小写(通常是一个类型的所有属性为String的情况下,例如,findByLastnameAndFirstnameAllIgnoreCase(…))。是否支持忽略示例可能会因存储而异,因此请参阅参考文档中的相关章节,了解特定于场景的查询方法。
  3. 可以通过OrderBy在引用属性和提供排序方向(Asc或Desc)的查询方法中附加一个子句来应用静态排序。要创建支持动态排序的查询方法来影响查询结果。

四、关键字列表

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age ⇐ ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … where x.age not in ?1
TRUE findByActiveTrue() … where x.active = true
FALSE findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

注意,除了find的前缀之外,我们查看PartTree的源码,还有如

下几种前缀:

private static final String QUERY_PATTERN = ” find | read | get | query | stream’;  
private static final String COUNT_PATTERN = "count"; 
private static final String EXISTS_PATTERN = "exists"; 
private static final String DELETE_PATTERN = "delete | remove';

使用的时候要配合不同的返回结果进行使用,例如:

interface UserRepository extends CrudRepository<User, Long> { 
long countByLastname (String lastname) ;//查询,总数 
long deleteByLastname (String lastname) ; / / 根据一个字段进行删除操作 
List<User> removeByLastname(String lastname);
}

五、方法的查询策略的属性表达式

属性表达式(Property Expressions)只能引用托管(泛化)实体的直接属性,如前一个示例所示。

在查询创建时,你已经确保解析的属性是托管实体的属性。同时,还可以通过遍历嵌套属性定义约束。

假设一个Person实体对象里面有一个Address属性里面包含一个ZipCode属性。在这种情况下,方法名为:

List<Person> findByAddressZipCode(String zipCode);

创建及其查找的过程是:

  1. 解析算法首先将整个part(AddressZipCode)解释为属性,并使用该名称(uncapitalized)检查域类的属性。
  2. 如果算法成功,就使用该属性。
  3. 如果不是,就拆分右侧驼峰部分的信号源到头部和尾部,并试图找出相应的属性,在我们的例子中是AddressZip和Code。
  4. 如果算法找到一个具有头部的属性,那么它需要尾部,并从那里继续构建树,然后按照刚刚描述的方式将尾部分割。
  5. 如果第一个分割不匹配,就将分割点移动到左边(Address、ZipCode),然后继续。

虽然这在大多数情况下应该起作用,但是算法可能会选择错误的属性。假设Person类也有一个addressZip属性,该算法将在第一个分割轮中匹配,并且基本上会选择错误的属性,最后失败(因为该类型addressZip可能没有code属性)。

要解决这个歧义,可以在方法名称中手动定义遍历点,所以我们的方法名称最终会是:

List<Person> findByAddress_ZipCode(String zipCode);

当然Spring JPA里面是将下划线视为保留字符,但是强烈建议遵循标准Java命名约定(不使用属性名称中的下划线,而是使用骆驼示例)。命名属性的时候注意一下这个特性。

可以到PartTreeJpaQuery.class 查询相关的method的name 拆分和实现逻辑。

原文  https://cn-blogs.cn/archives/8460.html
正文到此结束
Loading...