spring-data-neo4j
Spring BootアプリケーションにSpring Data Neo4jを統合し、グラフデータベースのノードエンティティを設定およびマッピングする方法をガイドし、Neo4jとのインタラクションを簡素化します。
npx skills add giuseppe-trisciuoglio/developer-kit --skill spring-data-neo4jBefore / After 効果比較
1 组Spring Data Neo4jのサポートがない場合、Spring Bootアプリケーションはグラフデータベースのノードとリレーションシップを管理するために複雑なNeo4jドライバーコードを手動で記述する必要がありました。データマッピングは煩雑でエラーが発生しやすく、開発効率が低く、メンテナンスコストが高額でした。
Spring Data Neo4jを統合した後、開発者はシンプルなPOJOエンティティとアノテーションを通じてNeo4jグラフデータベースとのシームレスな対話を実現できます。これにより、グラフデータ操作、エンティティマッピング、および開発プロセスが大幅に簡素化され、開発効率が著しく向上しました。
description SKILL.md
spring-data-neo4j
Spring Data Neo4j Integration Patterns
When to Use This Skill
To use this skill when you need to:
-
Set up Spring Data Neo4j in a Spring Boot application
-
Create and map graph node entities and relationships
-
Implement Neo4j repositories with custom queries
-
Write Cypher queries using
@Query annotations -
Configure Neo4j connections and dialects
-
Test Neo4j repositories with embedded databases
-
Work with both imperative and reactive Neo4j operations
-
Map complex graph relationships with bidirectional or unidirectional directions
-
Use Neo4j's internal ID generation or custom business keys
Overview
Spring Data Neo4j provides three levels of abstraction for Neo4j integration:
-
Neo4j Client: Low-level abstraction for direct database access
-
Neo4j Template: Medium-level template-based operations
-
Neo4j Repositories: High-level repository pattern with query derivation
Key features include reactive and imperative operation modes, immutable entity mapping, custom query support via @Query annotation, Spring's Conversion Service integration, and full support for graph relationships and traversals.
Instructions
Set Up Spring Data Neo4j
Add the dependency:
Maven: spring-boot-starter-data-neo4j
-
Gradle:
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
Configure connection properties:
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=secret
Configure Cypher-DSL dialect (recommended):
@Bean
Configuration cypherDslConfiguration() {
return Configuration.newConfig()
.withDialect(Dialect.NEO4J_5).build();
}
Define Node Entities
-
Use
@Node annotation to mark entity classes -
Choose ID strategy:
Business key as @Id (immutable, natural identifier)
-
Generated
@Id@GeneratedValue (Neo4j internal ID) -
Define relationships with
@Relationship annotation -
Keep entities immutable with final fields
-
Use
@Property for custom property names
Create Repositories
- Extend appropriate repository interface:
Neo4jRepository<Entity, ID> for imperative operations
-
ReactiveNeo4jRepository<Entity, ID>for reactive operations -
Use query derivation for simple queries
-
Apply
@Query annotation for complex Cypher queries -
Use $paramName syntax for parameters
Test Your Implementation
-
Use
@DataNeo4jTest for repository testing -
Set up Neo4j Harness with test fixtures
-
Test both positive and edge cases
-
Clean up test data between tests
Quick Setup
Dependencies
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
Gradle:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
}
Configuration
application.properties:
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=secret
Configure Neo4j Cypher-DSL Dialect:
@Configuration
public class Neo4jConfig {
@Bean
Configuration cypherDslConfiguration() {
return Configuration.newConfig()
.withDialect(Dialect.NEO4J_5).build();
}
}
Basic Entity Mapping
Node Entity with Business Key
@Node("Movie")
public class MovieEntity {
@Id
private final String title; // Business key as ID
@Property("tagline")
private final String description;
private final Integer year;
@Relationship(type = "ACTED_IN", direction = Direction.INCOMING)
private List<Roles> actorsAndRoles = new ArrayList<>();
@Relationship(type = "DIRECTED", direction = Direction.INCOMING)
private List<PersonEntity> directors = new ArrayList<>();
public MovieEntity(String title, String description, Integer year) {
this.title = title;
this.description = description;
this.year = year;
}
}
Node Entity with Generated ID
@Node("Movie")
public class MovieEntity {
@Id @GeneratedValue
private Long id;
private final String title;
@Property("tagline")
private final String description;
public MovieEntity(String title, String description) {
this.id = null; // Never set manually
this.title = title;
this.description = description;
}
// Wither method for immutability with generated IDs
public MovieEntity withId(Long id) {
if (this.id != null && this.id.equals(id)) {
return this;
} else {
MovieEntity newObject = new MovieEntity(this.title, this.description);
newObject.id = id;
return newObject;
}
}
}
Repository Patterns
Basic Repository Interface
@Repository
public interface MovieRepository extends Neo4jRepository<MovieEntity, String> {
// Query derivation from method name
MovieEntity findOneByTitle(String title);
List<MovieEntity> findAllByYear(Integer year);
List<MovieEntity> findByYearBetween(Integer startYear, Integer endYear);
}
Reactive Repository
@Repository
public interface MovieRepository extends ReactiveNeo4jRepository<MovieEntity, String> {
Mono<MovieEntity> findOneByTitle(String title);
Flux<MovieEntity> findAllByYear(Integer year);
}
Imperative vs Reactive:
-
Use
Neo4jRepositoryfor blocking, imperative operations -
Use
ReactiveNeo4jRepositoryfor non-blocking, reactive operations -
Do not mix imperative and reactive in the same application
-
Reactive requires Neo4j 4+ on the database side
Custom Queries with @Query
@Repository
public interface AuthorRepository extends Neo4jRepository<Author, Long> {
@Query("MATCH (b:Book)-[:WRITTEN_BY]->(a:Author) " +
"WHERE a.name = $name AND b.year > $year " +
"RETURN b")
List<Book> findBooksAfterYear(@Param("name") String name,
@Param("year") Integer year);
@Query("MATCH (b:Book)-[:WRITTEN_BY]->(a:Author) " +
"WHERE a.name = $name " +
"RETURN b ORDER BY b.year DESC")
List<Book> findBooksByAuthorOrderByYearDesc(@Param("name") String name);
}
Custom Query Best Practices:
-
Use
$parameterNamefor parameter placeholders -
Use
@Paramannotation when parameter name differs from method parameter -
MATCH specifies node patterns and relationships
-
WHERE filters results
-
RETURN defines what to return
Testing Strategies
Neo4j Harness for Integration Testing
Test Configuration:
@DataNeo4jTest
class BookRepositoryIntegrationTest {
private static Neo4j embeddedServer;
@BeforeAll
static void initializeNeo4j() {
embeddedServer = Neo4jBuilders.newInProcessBuilder()
.withDisabledServer() // No HTTP access needed
.withFixture(
"CREATE (b:Book {isbn: '978-0547928210', " +
"name: 'The Fellowship of the Ring', year: 1954})" +
"-[:WRITTEN_BY]->(a:Author {id: 1, name: 'J. R. R. Tolkien'}) " +
"CREATE (b2:Book {isbn: '978-0547928203', " +
"name: 'The Two Towers', year: 1956})" +
"-[:WRITTEN_BY]->(a)"
)
.build();
}
@AfterAll
static void stopNeo4j() {
embeddedServer.close();
}
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", embeddedServer::boltURI);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", () -> "null");
}
@Autowired
private BookRepository bookRepository;
@Test
void givenBookExists_whenFindOneByTitle_thenBookIsReturned() {
Book book = bookRepository.findOneByTitle("The Fellowship of the Ring");
assertThat(book.getIsbn()).isEqualTo("978-0547928210");
}
}
Examples
Example 1: Saving and Retrieving Entities
Input:
MovieEntity movie = new MovieEntity("The Matrix", "Welcome to the Real World", 1999);
movieRepository.save(movie);
MovieEntity found = movieRepository.findOneByTitle("The Matrix");
Output:
MovieEntity{
title="The Matrix",
description="Welcome to the Real World",
year=1999,
actorsAndRoles=[],
directors=[]
}
Example 2: Custom Cypher Query
Input:
List<Book> books = authorRepository.findBooksAfterYear("J.R.R. Tolkien", 1950);
Output:
[
Book{isbn="978-0547928210", name="The Fellowship of the Ring", year=1954},
Book{isbn="978-0547928203", name="The Two Towers", year=1956},
Book{isbn="978-0547928227", name="The Return of the King", year=1957}
]
Example 3: Relationship Traversal
Input:
@Query("MATCH (m:Movie)<-[:ACTED_IN]-(a:Person) " +
"WHERE m.title = $title RETURN a.name as actorName")
List<String> findActorsByMovieTitle(@Param("title") String title);
List<String> actors = movieRepository.findActorsByMovieTitle("The Matrix");
Output:
["Keanu Reeves", "Laurence Fishburne", "Carrie-Anne Moss", "Hugo Weaving"]
Progress from basic to advanced examples covering complete movie database, social network patterns, e-commerce product catalogs, custom queries, and reactive operations.
See examples for comprehensive code examples.
Best Practices
Entity Design
-
Use immutable entities with final fields
-
Choose between business keys (
@Id) or generated IDs (@Id@GeneratedValue) -
Keep entities focused on graph structure, not business logic
-
Use proper relationship directions (INCOMING, OUTGOING, UNDIRECTED)
Repository Design
-
Extend
Neo4jRepositoryfor imperative orReactiveNeo4jRepositoryfor reactive -
Use query derivation for simple queries
-
Write custom
@Query for complex graph patterns -
Don't mix imperative and reactive in same application
Configuration
-
Always configure Cypher-DSL dialect explicitly
-
Use environment-specific properties for credentials
-
Never hardcode credentials in source code
-
Configure connection pooling based on load
Testing
-
Use Neo4j Harness for integration tests
-
Provide test data via
withFixture()Cypher queries -
Use
@DataNeo4jTestfor test slicing -
Test both successful and edge-case scenarios
Architecture
-
Use constructor injection exclusively
-
Separate domain entities from DTOs
-
Follow feature-based package structure
-
Keep domain layer framework-agnostic
Security
-
Use Spring Boot property overrides for credentials
-
Configure proper authentication and authorization
-
Validate input parameters in service layer
-
Use parameterized queries to prevent Cypher injection
Constraints and Warnings
-
Do not mix imperative and reactive repositories in the same application.
-
Neo4j transactions are required for write operations; ensure
@Transactionalis properly configured. -
Be cautious with deep relationship traversal as it can cause performance issues.
-
Large result sets should be paginated to avoid memory problems.
-
Cypher queries are case-sensitive; ensure consistent casing in property names.
-
Immutable entities require proper wither methods for generated IDs.
-
Relationships in Spring Data Neo4j are not lazy-loaded by default; consider projection for large graphs.
-
The Neo4j Java driver is not compatible with reactive streams; use the reactive driver for reactive operations.
References
For detailed documentation including complete API reference, Cypher query patterns, and configuration options:
External Resources
Weekly Installs318Repositorygiuseppe-trisci…oper-kitGitHub Stars167First SeenFeb 3, 2026Security AuditsGen Agent Trust HubPassSocketPassSnykPassInstalled onclaude-code247gemini-cli237opencode236cursor231codex230github-copilot215
forumユーザーレビュー (0)
レビューを書く
レビューなし
統計データ
ユーザー評価
この Skill を評価