目录
Spring Data的Repository接口提供了通过方法名称自动生成查询逻辑的能力。
在Spring Data Neo4j中,继承Neo4jRepository接口同样可以获得这种按方法名自动生成查询逻辑的功能。
查询的默认深度为1,即查询本节点以及和本节点有直接关系的节点,查询的关系类型为节点实体类(使用@NodeEntity注解)中定义的关系类型。可以使用@Depth注解直接改变当前方法的查询深度,也可以使用(@Depth int depth)定义为方法的一个参数,根据传入参数决定查询深度,0为只查询本节点不查询关系,-1为无限延申。
package com.study.neo4j.dao;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import com.study.neo4j.bean.node.Person;
public interface PersonRepository extends Neo4jRepository<Person,Long> {
//@Depth(value=2)
Person findByName(String name);
}
该机制从方法中剥离前缀find…By、read…By、query…By、count…By和get…By,并开始解析其余部分。
方法名称可以包含表达式,比如Distinct。
第一个By充当分隔符,其后为查询条件。
可以使用And和Or连接多个属性的条件。
默认是相等比较,也可以使用Between, LessThan, GreaterThan,Like,Containing等比较方式。
可以使用IgnoreCase忽略单个属性的大小写或者AllIgnoreCase忽略所有属性的大小写。
可以使用OrderBy做排序,使用Asc和Desc指定排序方向。
示例如下:
// 返回 属性lastname=参数1 的记录条数
long countByLastname(String lastname);
// 删除 属性lastname=参数1 的记录并返回删除条数
long deleteByLastname(String lastname);
// 删除 属性lastname=参数1 的记录并返回删除的记录
List<User> removeByLastname(String lastname);
// 返回 属性lastname=参数1 的记录
List<Person> findByLastname(String lastname);
// 返回 属性emailAddress=参数1 并且 属性lastname=参数2 的记录
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// 返回 属性lastname=参数1 或者 属性firstname=参数2 的去重后的记录
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// 返回 属性lastname=参数1(忽略大小写) 的记录
List<Person> findByLastnameIgnoreCase(String lastname);
// 返回 属性lastname=参数1(忽略大小写) 并且 属性firstname=参数2(忽略大小写) 的记录
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// 返回 属性lastname=参数1 的记录并按firstname升序排列
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
// 返回 属性lastname=参数1 的记录并按firstname降序排列
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
属性表达式的自动解析,比如
List<Person> findByAddressZipCode(ZipCode zipCode);
在解析的时候,按照骆驼命名法进行从右往左的拆分,并依次判断是否存在,如果存在就使用,如果不存在再次重新拆分。
第一步 拆分为AddressZip和Code,判断类结构是不是 x.addressZip.code,如果是就停止,否者进行第二部判断
第二步 拆分为Address和ZipCode,判断类结构是不是 x.address.zipCode,如果是就停止,否者继续......
这种方法在多数情况下结果是对的,但有时候也会出错,比如既存在 x.address又存在 x.addressZip 的时候,就自动选择了addressZip的分支。
为了避免这种情况,可以使用"_"做强制分割。
List<Person> findByAddress_ZipCode(ZipCode zipCode);
在解析的时候就会匹配 x.address的结构
Pageable和Sort可以用来自动分页和排序。
Page<User> findByLastname(String lastname, Pageable pageable);
Slice<User> findByLastname(String lastname, Pageable pageable);
List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);
• Pageable和Sort不支持NULL值,如果要指定不分页和不排序可以使用Sort.unsorted()和Pageable.unpaged()对象。
• Pageable的属性里包含Sort
• 返回Page和Slice的处理是不一样。
返回Page的时候,会额外多发行一个count的查询来统计全体件数,可以让Page对象知道全体件数和分页数。
Page的实际查询会取当前分页的数据,而Slice的实际查询会取当前分页的每页件数+1件,多出来的一件用来判断Slice是否有后续数据hasNext()
// 简单的生成Sort
Sort sort = Sort.by("firstname").ascending()
.and(Sort.by("lastname").descending());
// 类型安全的方式生成Sort
TypedSort<Person> person = Sort.sort(Person.class);
Sort sort = person.by(Person::getFirstname).ascending()
.and(person.by(Person::getLastname).descending());
这是Spring Data的机能定义,在Spring Data Neo4j里面不支持,可能是因为neo4j里没有top和first语法吧。
// 取得第一件
User findFirstByOrderByLastnameAsc();
// 取得第一件
User findTopByOrderByAgeDesc();
// 取得分页的前10件
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
// 取得分页的前3件
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
// 取得前10件
List<User> findFirst10ByLastname(String lastname, Sort sort);
// 取得分页的前10件
List<User> findTop10ByLastname(String lastname, Pageable pageable);