最新的稳定版本请使用 Spring Data Neo4j 7.3.1Spring中文文档

最新的稳定版本请使用 Spring Data Neo4j 7.3.1Spring中文文档

如上所述,投影有两种类型:接口投影和基于 DTO 的投影。 在 Spring Data Neo4j 中,这两种类型的投影都直接影响到传输哪些属性和关系 通过电线。 因此,这两种方法都可以减少数据库的负载,以防您处理的节点和实体包含 应用程序中的所有使用方案中可能都不需要许多属性。Spring中文文档

对于基于接口和 DTO 的投影,Spring Data Neo4j 将使用存储库的域类型来构建 查询。将考虑可能更改查询的所有属性的所有批注。 域类型是通过存储库声明定义的类型 (给定一个像域类型的声明将是 )。interface TestRepository extends CrudRepository<TestEntity, Long>TestEntitySpring中文文档

基于接口的投影将始终是基础域类型的动态代理。定义的访问器的名称 在这样的接口上(如 ),必须解析为投影实体上存在的属性(此处:)。 这些属性在域类型上是否具有访问器并不重要,只要可以通过以下方式访问它们即可 通用的 Spring Data 基础结构。后者已经得到保证,因为域类型不会是 第一名。getNamenameSpring中文文档

与自定义查询一起使用时,基于 DTO 的投影在某种程度上更加灵活。而标准查询派生自 原始域类型,因此只能使用其中定义的属性和关系,自定义查询 可以添加其他属性。Spring中文文档

规则如下:首先,域类型的属性用于填充 DTO。如果 DTO 声明 其他属性 - 通过访问器或字段 - Spring Data Neo4j 在生成的记录中查找匹配的属性。 属性必须按名称完全匹配,并且可以是简单类型(如 中所定义) 或已知的持久性实体。支持这些集合,但不支持地图。org.springframework.data.neo4j.core.convert.Neo4jSimpleTypesSpring中文文档

多级投影

Spring Data Neo4j 还支持多级投影。Spring中文文档

多级投影示例
interface ProjectionWithNestedProjection {

    String getName();

    List<Subprojection1> getLevel1();

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

    interface Subprojection2 {
        String getName();
    }
}

即使可以对循环投影进行建模或指向将创建循环的实体, 投影逻辑不会遵循这些周期,而只会创建无周期查询。Spring中文文档

多级投影受限于它们应投影的实体。 在这种情况下,属于实体类别,如果应用预测,则需要得到尊重。RelationshipPropertiesSpring中文文档

预测的数据操作

如果已将投影提取为 DTO,则可以修改其值。 但是,如果您使用的是基于界面的投影,则不能只更新界面。 可以使用的典型模式是在域实体类中提供一种方法,该方法使用接口并使用从接口复制的值创建域实体。 这样,您就可以更新实体,并使用投影蓝图/蒙版再次保留它,如下一节所述。Spring中文文档

预测的持久性

与通过投影检索数据类似,它们也可以用作持久性的蓝图。 它提供了一个流畅的 API,用于将这些投影应用于保存操作。Neo4jTemplateSpring中文文档

您可以保存给定域类的投影Spring中文文档

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

或者,您可以保存域对象,但仅遵循投影中定义的字段。Spring中文文档

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

在这两种情况下,也可用于基于集合的操作,只有字段和关系 投影中定义的内容将得到更新。Spring中文文档

为防止删除数据(例如删除关系), 您应始终至少加载以后应保留的所有数据。
为防止删除数据(例如删除关系), 您应始终至少加载以后应保留的所有数据。

一个完整的例子

给定以下实体、预测和相应的存储库:Spring中文文档

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

    private String name;

    @Property("a_property") (1)
    private String aProperty;
}
1 此属性在图形中具有不同的名称
派生实体,继承自TestEntity
@Node
class ExtendedTestEntity extends TestEntity {

    private String otherAttribute;
}
界面投影TestEntity
interface TestEntityInterfaceProjection {

    String getName();
}
的 DTO 投影,包括一个附加属性TestEntity
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 投影图元上不存在此属性

下面显示了一个存储库,它的行为将如清单中所述。TestEntitySpring中文文档

存储库TestEntity
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 存储库的域类型为TestEntity
2 返回一个或多个方法将仅返回它的实例,因为它与域类型匹配TestEntity
3 返回扩展域类型的类的一个或多个实例的方法将仅返回实例 扩展类。所讨论方法的域类型将是扩展类,它 仍然满足存储库本身的域类型
4 此方法返回接口投影,因此该方法的返回类型不同 从存储库的域类型。接口只能访问域类型中定义的属性。 需要后缀才能使 SDN 不查找在ByInterfaceProjectionsTestEntity
5 此方法返回 DTO 投影。执行它将导致 SDN 发出警告,因为 DTO 定义为附加属性,该属性不在域类型的协定中。 在查询中,带注释的属性将正确转换为。 如上所述,返回类型与存储库的域类型不同。 需要后缀才能使 SDN 不查找在numberOfRelationsaPropertyTestEntitya_propertyByDTOProjectionsTestEntity
6 此方法还返回 DTO 投影。但是,不会发出警告,因为查询包含管接头 投影中定义的其他属性的值
而上面列表中的存储库使用具体的返回类型来 定义投影,另一种变体是使用动态投影,如 Spring Data Neo4j 与其他 Spring Data 项目共享的部分文档。动态投影可以是 适用于闭合和开放接口投影以及基于类的 DTO 投影:

动态投影的关键是将所需的投影类型指定为查询方法的最后一个参数 在这样的存储库中: .这是一个声明 可以添加到上述内容中,并允许通过相同的方法检索不同的投影,而无需 对几种方法重复可能的注释。
<T> Collection<T> findByName(String name, Class<T> type)TestRepository@Query
1 此属性在图形中具有不同的名称
1 投影图元上不存在此属性
1 存储库的域类型为TestEntity
2 返回一个或多个方法将仅返回它的实例,因为它与域类型匹配TestEntity
3 返回扩展域类型的类的一个或多个实例的方法将仅返回实例 扩展类。所讨论方法的域类型将是扩展类,它 仍然满足存储库本身的域类型
4 此方法返回接口投影,因此该方法的返回类型不同 从存储库的域类型。接口只能访问域类型中定义的属性。 需要后缀才能使 SDN 不查找在ByInterfaceProjectionsTestEntity
5 此方法返回 DTO 投影。执行它将导致 SDN 发出警告,因为 DTO 定义为附加属性,该属性不在域类型的协定中。 在查询中,带注释的属性将正确转换为。 如上所述,返回类型与存储库的域类型不同。 需要后缀才能使 SDN 不查找在numberOfRelationsaPropertyTestEntitya_propertyByDTOProjectionsTestEntity
6 此方法还返回 DTO 投影。但是,不会发出警告,因为查询包含管接头 投影中定义的其他属性的值
而上面列表中的存储库使用具体的返回类型来 定义投影,另一种变体是使用动态投影,如 Spring Data Neo4j 与其他 Spring Data 项目共享的部分文档。动态投影可以是 适用于闭合和开放接口投影以及基于类的 DTO 投影:

动态投影的关键是将所需的投影类型指定为查询方法的最后一个参数 在这样的存储库中: .这是一个声明 可以添加到上述内容中,并允许通过相同的方法检索不同的投影,而无需 对几种方法重复可能的注释。
<T> Collection<T> findByName(String name, Class<T> type)TestRepository@Query