对于最新稳定版本,请使用Spring Data Neo4j 8.0.0spring-doc.cadn.net.cn

Spring Data Neo4j 预测

如上所述,投影有两种类型:接口投影和基于DTO的投影。在Spring Data Neo4j中,这两种投影都直接影响哪些属性和关系被传输通过线路传输。因此,如果你处理的节点和实体包含许多属性,而这些属性可能并非所有应用场景都需要。spring-doc.cadn.net.cn

无论是基于接口还是基于DTO的投影,Spring Data Neo4j都会使用仓库的域类型来构建 查询。 所有可能改变查询的属性的注释都会被考虑。域类型是通过仓库声明定义的类型(给定一个声明,如interface TestRepository 扩展了 CrudRepository<TestEntity, Long>域名类型为测试实体).spring-doc.cadn.net.cn

基于接口的投影始终是底层域类型的动态代理。访问器名称在此类接口上定义(如getName)必须解析为性质(此处:名称)这些元素存在于投影实体上。这些属性是否在域类型上有访问者并不重要,只要它们可以通过公共的 Spring Data 基础设施访问。后者已经被确保了,因为该域名类型本身就不会是一个持久实体本来就如此。spring-doc.cadn.net.cn

基于DTO的投影在与自定义查询结合时会更灵活一些。虽然标准查询源自原始领域类型,因此只能使用其中定义的属性和关系,但自定义查询可以添加额外的属性。spring-doc.cadn.net.cn

规则如下:首先,利用域类型的属性填充 DTO。如果 DTO 声明额外属性——通过访问器或字段——Spring Data Neo4j 会在结果记录中查找匹配的属性。属性必须通过名称完全匹配,且可以是简单类型(如定义于org.springframework.data.neo4j.core.convert.Neo4jSimpleTypes) 或已知持久实体的集合。支持这些集合,但不支持映射。spring-doc.cadn.net.cn

多层次投影

Spring Data Neo4j 还支持多层次投影。spring-doc.cadn.net.cn

多层投影示例
interface ProjectionWithNestedProjection {

    String getName();

    List<Subprojection1> getLevel1();

    interface Subprojection1 {
        String getName();
        List<Subprojection2> getLevel2();
    }

    interface Subprojection2 {
        String getName();
    }
}

尽管可以建模循环投影或指向会创建循环的实体,投影逻辑不会遵循这些循环,只会创建无循环的查询。spring-doc.cadn.net.cn

多层投影受限于它们应投影的实体。关系属性在这种情况下,属于实体类别,如果应用投影,就需要得到尊重。spring-doc.cadn.net.cn

投影的数据作

如果你已经将投影作为DTO获取,可以修改其值。 但如果你使用基于接口的投影,你不能仅仅更新界面。 一个典型的模式是在你的域实体类中提供一个方法,消耗接口并创建一个包含从接口复制的值的域实体。 这样,你可以更新实体,并像下一节描述的投影蓝图/遮罩一样再次持久化。spring-doc.cadn.net.cn

投影的持久性

类似于通过投影检索数据,它们也可以作为持久化的蓝图。 这Neo4j模板提供流畅的 API,将这些投影应用到保存作中。spring-doc.cadn.net.cn

你可以为某个域类保存投影spring-doc.cadn.net.cn

给定域类的保存投影
Projection projection = neo4jTemplate.save(DomainClass.class).one(projectionValue);

或者你可以保存一个域对象,但只尊重投影中定义的字段。spring-doc.cadn.net.cn

保存域对象并使用给定的投影蓝图
Projection projection = neo4jTemplate.saveAs(domainObject, Projection.class);

在这两种情况下,这些作也可用于基于集合的作,仅限字段和关系 投影中定义的将被更新。spring-doc.cadn.net.cn

为了防止数据的删除(例如删除关系), 你应该至少加载所有之后需要持久化的数据。

完整示例

给定以下实体、投影及相应的存储库:spring-doc.cadn.net.cn

一个简单的实体
@Node
class TestEntity {
    @Id @GeneratedValue private Long id;

    private String name;

    @Property("a_property") (1)
    private String aProperty;
}
1 该性质在图中有不同的名称
衍生实体,继承于测试实体
@Node
class ExtendedTestEntity extends TestEntity {

    private String otherAttribute;
}
界面投影测试实体
interface TestEntityInterfaceProjection {

    String getName();
}
DTO 投影测试实体,包括一个额外的属性
class TestEntityDTOProjection {

    private String name;

    private Long numberOfRelations; (1)

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getNumberOfRelations() {
        return numberOfRelations;
    }

    public void setNumberOfRelations(Long numberOfRelations) {
        this.numberOfRelations = numberOfRelations;
    }
}
1 该属性不存在于投影实体中

一个测试实体如下所示,且其行为将如同商品列表所述。spring-doc.cadn.net.cn

一个用于测试实体
interface TestRepository extends CrudRepository<TestEntity, Long> { (1)

    List<TestEntity> findAll(); (2)

    List<ExtendedTestEntity> findAllExtendedEntities(); (3)

    List<TestEntityInterfaceProjection> findAllInterfaceProjectionsBy(); (4)

    List<TestEntityDTOProjection> findAllDTOProjectionsBy(); (5)

    @Query("MATCH (t:TestEntity) - [r:RELATED_TO] -> () RETURN t, COUNT(r) AS numberOfRelations") (6)
    List<TestEntityDTOProjection> findAllDTOProjectionsWithCustomQuery();
}
1 仓库的域类型为测试实体
2 返回一个或多个的方法测试实体只返回实例,因为它与域类型相符
3 返回一个或多个扩展域类型的类实例的方法只返回实例 扩展阶级的成员。该方法的域类型将是扩展类,其中 仍然满足仓库本身的域类型
4 该方法返回接口投影,因此返回类型不同 来自仓库的域名类型。该接口只能访问域类型中定义的属性。 后缀是让 SDN 不去寻找接口投影测试实体
5 该方法返回 DTO 投影。执行该警告会使SDN发出警告,正如DTO所定义的关系数量作为附加属性,但该属性不在域类型的契约中。 注释属性aProperty测试实体将正确翻译为a_property在查询中。 如上所述,返回类型与仓库的域类型不同。 后缀是让 SDN 不去寻找DTOProjections测试实体
6 该方法还返回 DTO 投影。但不会发出警告,因为查询包含配对 投影中定义的额外属性值
上述列表中的仓库使用了一个具体的返回类型 定义投影,另一种变体是动态投影的使用,详见 Spring Data Neo4j 与其他 Spring Data 项目共享的部分文档。动态投影可以为 应用于封闭接口投影和开放接口投影以及基于类的DTO投影:

动态投影的关键是将期望投影类型指定为查询方法的最后一个参数 在这样的仓库中:
<T> Collection<T> findByName(字符串名,类<T>类型).这是一项声明 可以添加到测试仓库上述,允许通过相同方法检索不同的投影,且 重复可能的@Query对多种方法的注释。