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

标签 java spring neo4j spring-data-neo4j

我有以下节点:

@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 类定义,以防止每次加载 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 查询语言编写的查询,可以解决我的问题。我如何使用当前的类设置在 Repository 方法中“翻译”它?

最佳答案

感谢您的提问。

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

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

请申报您的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。与您已经编写的查询非常相似。请注意,您还必须返回开始和结束节点才能使映射工作。

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

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

在当前版本的 Spring Data Neo4j 和随 Spring Boot 2.1.8 分发的 Neo4j-OGM 中,可以激活它们,如下面的测试所示(向下滚动到带 Config 注释的 @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 .想要查看我本地运行的实例中创建的数据。

我还建议不要在测试中使用嵌入式数据库,而是测试容器,也就是您将在生产中运行的“真实事物”: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>

关于java - 如何使用@StartNode 关系查询 Neo4jRepository?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57852233/

相关文章:

java - java.awt.Window 的全屏问题

java - 同时扫描 double 和 char 值

neo4j - 连接到同一网络上不同计算机上的 neo4j?

java - 如何在 Android 中将字符串转换为 UTF-8?

java - 异常中的空堆栈跟踪

Spring @PathVariable 集成测试

java - 从 Controller 中的最后一次插入中获取生成的 Id,Spring

java - 在 For 循环内部或外部声明对象 - Spring

java - Neo4j双向遍历api

python - Unicode编码错误: bulbs and neo4j create Model