You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -13,7 +13,7 @@ We using following technology stack to deal with persistence:
13
13
14
14
- Embedded Cassandra as direct storage (`CassandraDaemon` allows to have the Cassandra instance inside same JVM as the application)
15
15
- JanusGraph as Graph DBMS (it is not directly a data storage, it just allows you to have access to data in the form of a graph)
16
-
-[Apache TinkerPop](http://tinkerpop.apache.org/docs/current/reference/) as a set of tools to interact with the database (mainly Gremlin meant here)
16
+
-[Apache TinkerPop](http://tinkerpop.apache.org/docs/current/reference/) as a set of tools to interact with the database
17
17
-[spring-data-neo4j](https://github.com/spring-projects/spring-data-neo4j) to manage transactions in Spring with `Neo4jTransactionManager` and implement custom Cypher queries with Spring Data repositories (by custom queries means `@org.springframework.data.neo4j.annotation.Query` annotation)
18
18
-[cypher-for-gremlin](https://github.com/opencypher/cypher-for-gremlin) which translates Cypher queries into Gremlin traversals (it has some issues which prevents us to use it for `neo4j-ogm` CRUD operations, these issues will be explained below)
19
19
-[neo4j-ogm](https://github.com/neo4j/neo4j-ogm) to map Java POJOs into Vertices and Edges of Graph
@@ -23,13 +23,6 @@ We using following technology stack to deal with persistence:
23
23
24
24
Unlike a Relational DBMS, Graph DBMS have vertices and edges, not rows and tables. So in terms of Graph every persistent entity should be stored as Vertex or Edge. An example of a vertex might be `Artifact` or `AritfactCoordinates` and the relation between them would be an edge. It should be noted that, unlike RDBMS, object relations are represented by separate edge instead of just foreign key column in table. In addition to vertices, persistence objects can also be an edges, as an example the `ArtifactDependency` would be an edge between `ArtifactCoordinates` vertices.
25
25
26
-
# Issues of `cypher-for-gremlin` and `neo4j-ogm`
27
-
28
-
First issue was the fact that `cypher-for-gremlin` not fully suport all Cypher syntax that produced by `neo4j-ogm` for CRUD operations. In more detail on every CRUD operation `neo4j-ogm` generate Cypher query which then translates into Gremlin by `cypher-for-gremlin`. As a workadound we modify Cypher queries produced by `neo4j-ogm` and replace some clauses (see `org.opencypher.gremlin.neo4j.ogm.request.GremlinRequest`).
29
-
30
-
Another issue is that `cypher-for-gremlin` have some doubtful concept to work with `null` values in Gremlin. They put a lot of noisy tokens into Gremlin traversals which prevents JanusGraph engine to match expected indexes, this causes heavy fullscan on every query (see [#342](https://github.com/opencypher/cypher-for-gremlin/issues/342)). This was the main reason of why we can't use `neo4j-ogm` for CRUD operations.
31
-
Anyway we still using it for custom Cypher queries with `@org.springframework.data.neo4j.annotation.Query` annotation. This is good option to have Cypher queries instead of Gremlin because it looks more clear and takes less time to read existing and write new queries.
32
-
33
26
## Gremlin Server
34
27
35
28
`TODO`
@@ -56,20 +49,22 @@ the `strongbox-data-service` module.
56
49
## Creating Your Entity Class
57
50
58
51
Let's now assume that you have a POJO and you need to save it to the database (and that you probably have at least
59
-
CRUD operation's implemented in it as well). Place your code under the `org.carlspring.strongbox.domain`
52
+
CRUD operations implemented in it as well). Place your code under the `org.carlspring.strongbox.domain`
60
53
package. For the sake of the example, let's pick `PetEntity` as the name of your entity.
61
54
62
55
If you want to store that entity properly you need to adopt the following rules:
63
56
64
-
* Create the interface for your entity with all getters and setters that required to interact with the entity according to the `JavaBeans` coding convention. This interface should extend `org.carlspring.strongbox.data.domain.DomainObject`. The need for an interface is due to hide the implementation specific to underlying database, such as inheritance strategy.
65
-
* Create the entity class which implements the above interface and have the `org.carlspring.strongbox.data.domain.DomainEntity` as the superclass.
57
+
* Create the interface for your entity with all getters and setters that required to interact with the entity, according to the `JavaBeans` coding convention. This interface should extend `org.carlspring.strongbox.data.domain.DomainObject`. The need for an interface is due to hide the implementation specific details depending on underlying database, such as inheritance strategy.
58
+
* Create the entity class which implements the above interface and have the `org.carlspring.strongbox.data.domain.DomainEntity` as the superclass.
59
+
* Declare entity class with `@NodeEntity` or `@RelationshipEntity`
66
60
* Define a default empty constructor, this would need to create entity instance from `neo4j-ogm` internals.
67
61
68
62
The complete source code example that follows all requirements should look something like this:
69
63
70
64
```java
71
65
packageorg.carlspring.strongbox.domain;
72
66
67
+
@NodeEntity("Pet")
73
68
publicclassPetEntity
74
69
extendsDomainEntity
75
70
implementsPet
@@ -96,14 +91,145 @@ public class PetEntity
96
91
}
97
92
```
98
93
99
-
#Gremlin Repositories
94
+
## Creating a `EntityTraversalAdapter`
100
95
101
-
As mentioned above besides `neo4j-ogm` we were forced to have custom CRUD implementation based on Gremlin. This has its advantages as it allow for us to optimize OGM entities and make them faster then common `neo4j-ogm` provide out of the box. The main thing of the Gremlin based CRUD is `EntityTraversalAdapter` which is a strategy for create/update, read/delete operations. The concrete `EntityTraversalAdapter` provide anonymous traversals for each of the operations on specific entity type. These traversals used in Gremlin based repositories to perform common CRUD operations. The `EntityTraversalAdapter` implementations can also use each other to support relations between entities, inheritance and cascade operations.
96
+
As mentioned above besides `neo4j-ogm`and `spring-data-neo4j`we were forced to use custom CRUD implementations based on Gremlin. This has its advantages as it allow for us to optimize OGM entities and make them faster then common `neo4j-ogm` provide out of the box. The main thing of the Gremlin based CRUD is `EntityTraversalAdapter` which is a strategy for create/update, read/delete operations. The concrete `EntityTraversalAdapter` provide [Anonymous traversals](http://tinkerpop.apache.org/docs/current/tutorials/gremlins-anatomy/) for each of the operations on specific entity type. These traversals used in Gremlin based repositories to perform common CRUD operations:
102
97
103
-
## Creating a `EntityTraversalAdapter`
104
-
`TODO`
98
+
-`fold` to construct entity instance based on Vertex/Edge and it's properties
99
+
-`unfold` to extract entity properties into Vertex/Edge and it's properties
100
+
-`cascade` to cascade other Vertices/Edges within delete if needed
101
+
102
+
The `EntityTraversalAdapter` implementations can also use each other to support relations between entities, inheritance and cascade operations.
103
+
104
+
Below is the code example of `EntityTraversalAdapter` implementation for `PetEntity`:
All the database interactions should be done through repositories. For the compatibility with `spring-data` we use `org.springframework.data.repository.CrudRepository` as a basis for our repositories. The base class for implementing `EntityTraversalAdapter`-based repositories is `org.carlspring.strongbox.gremlin.repositories.GremlinRepository`. Further repository implementation depends on the type of entity, for Vertex backed entities it should be `GremlinVertexRepository`.
177
+
In addition to CRUD operations, there is also need the ability to select data using queries. Queries could be implemented using [Cypher](https://neo4j.com/docs/cypher-manual/current/introduction/) through `spring-data-neo4j` and `@org.springframework.data.neo4j.annotation.Query` annotation. So the final repository should be a class that extends `GremlinRepository` and delegates custom `Cypher` queries into `org.springframework.data.repository.Repository` instance provided by `spring-data-neo4j`.
178
+
179
+
Putting all above together the repository for the `PetEntity` will looks like below:
First issue was the fact that `cypher-for-gremlin` not fully suport all Cypher syntax that produced by `neo4j-ogm` for CRUD operations. In more detail on every CRUD operation `neo4j-ogm` generate Cypher query which then translates into Gremlin by `cypher-for-gremlin`. As a workadound we modify Cypher queries produced by `neo4j-ogm` and replace some clauses (see `org.opencypher.gremlin.neo4j.ogm.request.GremlinRequest`).
231
+
232
+
Another issue is that `cypher-for-gremlin` have some doubtful concept to work with `null` values in Gremlin. They put a lot of noisy tokens into Gremlin traversals which prevents JanusGraph engine to match expected indexes, this causes heavy fullscan on every query (see [#342](https://github.com/opencypher/cypher-for-gremlin/issues/342)). This was the main reason of why we can't use `neo4j-ogm` for CRUD operations.
233
+
Anyway we still using it for custom Cypher queries with `@org.springframework.data.neo4j.annotation.Query` annotation. This is good option to have Cypher queries instead of Gremlin because it looks more clear and takes less time to read existing and write new queries.
0 commit comments