Spring Data Neo4j: фильтр по LocalDate не работает - PullRequest
0 голосов
/ 20 сентября 2018

Мое маленькое приложение Neo4j для игровых площадок (на основе Spring Boot 2, Spring Data Neo4j и встроенного драйвера) представляет собой небольшое программное обеспечение для ведения заметок.Пользователи могут фильтровать свои заметки по дате создания.Чтобы лучше понять Cypher, я написал запрос Cypher с использованием SDN @Query (NoteRepo.findByDay(day)).

Однако я не могу заставить работать фильтрацию.Я запутался, что LocalDate был преобразован в карту (последняя строка вывода консоли).В предыдущем запросе (NoteRepo.findBySnoozeUntil(day), используя ключевые слова репо-запроса SDN) все было хорошо, и day был преобразован в дату ISO 8601.

Может кто-нибудь указать, что с ним не так и исправить?

Note.java

@NodeEntity
class Note {
    @Id
    @GeneratedValue
    private Long id;
    private String content;
    private LocalDateTime created;
    private LocalDate snoozedUntil;
    // constructors, getters, setters, ... omitted
}

NoteRepo.java

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

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

interface NoteRepo extends Neo4jRepository<Note, Long> {
    // FIXME find all notes created on a specific day
    // currently returns an empty list
    @Query("MATCH (n: Note) WHERE date(datetime(n.created)) = {0} RETURN n")
    List<Note> findByDay(LocalDate day);

    List<Note> findBySnoozeUntil(LocalDate day);
}

App.java

package com.example.neo4jquerywithlocaldate;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.time.LocalDate;
import java.time.LocalDateTime;

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        var ctx = SpringApplication.run(App.class, args);
        var repo = ctx.getBean(NoteRepo.class);
        var tomorrow = LocalDate.now().plusDays(1);
        repo.save(new Note("learn neo4j", LocalDateTime.now(), tomorrow));

        var notesForTomorrow = repo.findBySnoozeUntil(tomorrow);
        System.out.println("notes snoozed until tomorrow = " + notesForTomorrow);

        var todaysNotes = repo.findByDay(LocalDate.now());
        System.out.println("today's notes = " + todaysNotes);
    }
}

консольный вывод приложения Spring Boot (урезано до запросов Neo4j и System.out.println)

UNWIND {rows} as row CREATE (n:`Note`) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-1, props={snoozeUntil=2018-09-21, created=2018-09-20T19:38:54.732260, content=learn neo4j}}]}

MATCH (n:`Note`) WHERE n.`snoozeUntil` = { `snoozeUntil_0` } WITH n RETURN n, ID(n) with params {snoozeUntil_0=2018-09-21}

< notes for tomorrow = [Note{id=0, content='learn neo4j', created=2018-09-20T19:38:54.732260}]

MATCH (n: Note) WHERE date(datetime(n.created)) = {0} RETURN n with params {0={year=2018, month=SEPTEMBER, monthValue=9, dayOfMonth=20, chronology={id=ISO, calendarType=iso8601}, dayOfWeek=THURSDAY, era=CE, dayOfYear=263, leapYear=false}}

< today's notes = []

repro project: Spring Initializr Project

добавьте это к build.gradle:

ext['neo4j-ogm.version'] = '3.1.3'

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
    runtimeOnly 'org.neo4j:neo4j:3.4.7'
    runtimeOnly 'org.neo4j:neo4j-ogm-embedded-driver:3.1.3'
}

и добавьте классы выше.

1 Ответ

0 голосов
/ 24 сентября 2018

В настоящий момент производные запросы (например, List<Note> findBySnoozedUntil(LocalDate day);) обрабатываются иначе, чем аннотированные @Query с использованием встроенного драйвера.

Встроенный драйвер в настоящее время отображает все параметры в строки.В двух случаях он безоговорочно использует экземпляр Jacksons ObjectMapper.

Нам нужно несколько шагов, чтобы это исправить.

  1. Научите ObjectMapper использовать разумный формат.Это просто, вы находитесь на Boot, поэтому, пожалуйста, добавьте этот стартер compile('org.springframework.boot:spring-boot-starter-json'), он приносит много полезных модулей Джексона.Если вы намереваетесь написать веб-приложение и у вас уже есть spring-boot-starter-web или spring-boot-starter-webflux, вы можете опустить стартер JSON, эти модули принесут его.

  2. Зарегистрировать включенную Java8 модулей Джексона с OGMs Embedded Objectmapper и отключение записи дат в качестве отметок времени, т. Е. В вашем классе приложений:

final ObjectMapper ogmObjectMapper = org.neo4j.ogm.config.ObjectMapperFactory.objectMapper();
ogmObjectMapper.registerModule(new JavaTimeModule());
ogmObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
Поскольку встроенный драйвер использует эту конфигурацию для сопоставления значения как String, вам, к сожалению, необходимо адаптировать запрос:
@Query("MATCH (n: Note) WHERE date(datetime(n.created)) = date({0}) RETURN n")
List<Note> findByDay(LocalDate day);

Теперь связанный вывод

2018-09-24 10:50:53.313  INFO 2860 --- [           main] o.n.o.d.e.request.EmbeddedRequest        : Request: MATCH (n:`Note`) WHERE n.`snoozedUntil` = { `snoozedUntil_0` } WITH n RETURN n, ID(n) with params {snoozedUntil_0=2018-09-25}
notes snoozed until tomorrow = [com.example.demo.Note@2420e962]
2018-09-24 10:50:53.522  INFO 2860 --- [           main] o.n.o.d.e.request.EmbeddedRequest        : Request: MATCH (n: Note) WHERE date(datetime(n.created)) = date({0}) RETURN n with params {0=2018-09-24}
today's notes = [com.example.demo.Note@363d3958]

Редактировать: Тот же эффект можно было бы увидеть при использовании Bolt и для внешней базы данных, решение в настоящее время такое же.

...