如何使用@StartNode 关系查询 Neo4jRepository?

How to query Neo4jRepository using a @StartNode relationship?

我有以下节点:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@NodeEntity
public class Person {

  @Id
  @GeneratedValue
  private Long id;

  private String firstName;

  private String lastName;

  private LocalDate birthday;

  @Email
  private String email;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@NodeEntity
public class Skill {

  @Id
  @GeneratedValue
  private Long id;

  private String name;

  private String description;
}

还有这个RelationshipEntity

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@RelationshipEntity("RATED")
public class SkillRating {

  @Id
  @GeneratedValue
  private Long id;

  @Min(0)
  @Max(100)
  private Integer score;

  private LocalDate measurementDate;

  @StartNode
  private Person person;

  @EndNode
  private Skill skill;
}

我不想加载我不打算使用的关系,即我不想添加:

@Relationship(type = "RATED")
private Set<SkillRating> skillRatings;

我的 Person class 定义,以防止我每次加载 Person 时加载这些评级。我想在必要时使用 Repository 方法加载它们。这是我尝试使用我对 JPA 存储库的了解:

@Repository
public interface SkillRatingRepository extends Neo4jRepository<SkillRating, Long> {
  List<SkillRating> findAllByPerson(Person person);
}

但是这个方法没有按预期工作,因为它没有找到任何人的评级。我做错了什么?

-- 编辑--

MATCH (p)-[r:RATED]->(skill) WHERE id(p)={personId} RETURN r

我相信这是一个用 Neo4j Cypher 查询语言编写的查询,可以解决我的问题。如何使用我当前的 class 设置以 Repository 方法 "translate" 它?

谢谢提问。

如您所见,我们不支持基于对象的派生查找器方法。 @RelationshipEntity 还有一个额外的限制,派生的查找器方法只针对属性而不是结束或开始节点。

话虽如此,我已经接受了您的项目(域 classes)并为您创建了一个解决方案。因此,域 classes PersonSkillSkillRating 可以按原样使用。

请这样声明您的SkillRatingRepository

import java.util.List;

import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;

public interface SkillRatingRepository extends Neo4jRepository<SkillRating, Long> {

    @Query("MATCH (p)-[r:RATED]->(skill) WHERE id(p) = :#{#person.id} RETURN p, r, skill")
    List<SkillRating> findAllByPerson(Person person);
}

@Query表示自定义查询。在该自定义查询中,您可以使用 Spring 表达式语言 (SpEL),如此处所述 https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions.

因此,您将取消引用已通过的人并访问该 ID。与您已经编写的查询非常相似。请注意,您还必须 return 开始和结束节点才能使映射工作。

如果您 运行 一个标准的 Spring 引导项目,那么参数名称会在编译期间保留,不需要其他注释。如果您不保留它们,请在参数中添加@Param("person")

我注意到您在您的域中使用 LocalDate。 Neo4j 3.4+ 和 Java(又名 Bolt)驱动程序原生支持这些。

在当前版本的 Spring Data Neo4j 和 Neo4j-OGM 与 Spring Boot 2.1.8 一起分发时,可以激活它们,如下面的测试所示(向下滚动到 Config class 注释为 @TestConfiguration):

import static org.assertj.core.api.Assertions.*;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.driver.ParameterConversionMode;
import org.neo4j.ogm.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

@SpringBootTest
@RunWith(SpringRunner.class)
@TestConfiguration
public class SkillRatingRepositoryTest {

    @Autowired
    private SkillRatingRepository skillRatingRepository;

    @Autowired
    private Session session;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Test
    public void retrievalOfSkillsShouldWork() {
        Skill s = Skill.builder().name("Java")
            .description("The Number one programming language everyone loves and hates").build();

        new TransactionTemplate(transactionManager).execute(t -> {
            session.purgeDatabase();
            return null;
        });

        Person ms = Person.builder()
            .firstName("Michael")
            .lastName("Simons")
            .build();
        Person gm = Person.builder()
            .firstName("Gerrit")
            .lastName("M")
            .build();
        SkillRating r1 = SkillRating
            .builder().person(ms)
            .skill(s).measurementDate(LocalDate.now()).score(23).build();
        SkillRating r2 = SkillRating
            .builder().person(gm)
            .skill(s).measurementDate(LocalDate.now()).score(42).build();

        skillRatingRepository.saveAll(Arrays.asList(r1, r2));

        List<SkillRating> skillRatings =
            skillRatingRepository.findAllByPerson(gm);
        assertThat(skillRatings).hasSize(1);
    }

    @TestConfiguration
    static class Config {

        @Bean
        public org.neo4j.ogm.config.Configuration configuration() {
            Configuration.Builder builder = new org.neo4j.ogm.config.Configuration.Builder();
            builder.uri("bolt://localhost:7687");
            builder.credentials("neo4j", "secret");
            builder.withCustomProperty(ParameterConversionMode.CONFIG_PARAMETER_CONVERSION_MODE,
                ParameterConversionMode.CONVERT_NON_NATIVE_ONLY);
            return builder.build();
        }
    }
}

请注意,我既没有使用嵌入式实例进行测试,也没有使用 @DataNeo4jTest。想要查看我本地 运行ning 实例中创建的数据。

我还建议不要在测试中使用嵌入式数据库,而是在生产中使用测试容器 "the real thing" 运行:https://medium.com/neo4j/testing-your-neo4j-based-java-application-34bef487cc3c

作为最终参考,这是我使用的 POM。如果这个东西有用并解决了您的问题,请采纳答案。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>neo4j</groupId>
    <artifactId>so_re</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>so_re</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-neo4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>