Split programming model into per-section files, and rearranged the chapter a bit, moving up sections on indexing and transactions.

This commit is contained in:
David Montag
2011-03-15 15:59:23 -07:00
parent e5f9c6b3bb
commit fcd777b08b
15 changed files with 689 additions and 587 deletions

View File

@@ -98,16 +98,16 @@
<xi:include href="reference/preface.xml"/>
<xi:include href="reference/neo4j.xml"/>
<xi:include href="reference/programming-model.xml"/>
<xi:include href="reference/programming-model/programming-model.xml"/>
<xi:include href="reference/setup.xml"/>
<xi:include href="reference/cross-store.xml"/>
<xi:include href="reference/samples.xml"/>
<xi:include href="reference/performance.xml" />
<xi:include href="reference/template.xml" />
<xi:include href="reference/annotations.xml" />
<xi:include href="reference/aspectj-intro.xml" />
<xi:include href="reference/neo4j-intro.xml" />
<xi:include href="reference/spring-data.xml" />
<xi:include href="reference/neo4j-server.xml" />
<!--<xi:include href="reference/performance.xml" />-->
<!--<xi:include href="reference/template.xml" />-->
<!--<xi:include href="reference/annotations.xml" />-->
<!--<xi:include href="reference/aspectj-intro.xml" />-->
<!--<xi:include href="reference/neo4j-intro.xml" />-->
<!--<xi:include href="reference/spring-data.xml" />-->
<!--<xi:include href="reference/neo4j-server.xml" />-->
</part>
</book>

View File

@@ -1,29 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="neo4j">
<title>Introduction to the Neo4j Graph Database</title>
<title>Introduction to Neo4j</title>
<para>
<ulink url="http://neo4j.org/">Neo4j</ulink> is a graph database, a fully transactional database that stores data structured as graphs. A graph is a flexible data structure that allows for a more agile and rapid style of development.
</para>
<ulink url="http://neo4j.org/">Neo4j</ulink> is a graph database. It is a fully transactional database that
stores data structured as graphs. A graph consists of nodes, connected by relationships. It is a flexible
data structure that allows for high query performance on complex data, while being intuitive for the
developer.
</para>
<para>
Neo4j has been in commercial development for 10 years and in production for over 7 years. It is a mature and robust graph database that provides:
<itemizedlist><listitem>
an intuitive graph-oriented model for data representation. Instead of static and rigid tables, rows and columns, you work with a flexible graph network consisting of <ulink url="http://wiki.neo4j.org/content/Getting_Started">nodes, relationships and properties</ulink>.
</listitem><listitem> a disk-based, native storage manager completely optimized for storing graph structures for maximum performance and scalability.
</listitem><listitem> massive scalability. Neo4j can handle graphs of several billion nodes/relationships/properties on a single machine and can be sharded to scale out across multiple machines.
</listitem><listitem> a powerful traversal framework for high-speed traversals in the node space.
</listitem><listitem> can be deployed as a full server or a very slim database with a small
footprint (~500k jar).
</listitem><listitem> a simple and convenient object-oriented <ulink url="http://api.neo4j.org/">API</ulink>.
</listitem></itemizedlist>
</para>
Neo4j has been in commercial development for 10 years and in production for over 7 years. It is a mature and
robust graph database that:
<itemizedlist>
<listitem>has an intuitive graph-oriented model for data representation. Instead of tables, rows, and columns,
you work with a flexible graph network consisting of
<ulink url="http://wiki.neo4j.org/content/Getting_Started">nodes, relationships, and properties</ulink>.
</listitem>
<listitem>has a disk-based, native storage manager completely optimized for storing graph structures for maximum
performance and scalability.
</listitem>
<listitem>is scalable. Neo4j can handle graphs of several billion nodes/relationships/properties on
a single machine, but can also be scaled out across multiple machines for high availability.
</listitem>
<listitem>has a powerful traversal framework for fast traversals in the node space.
</listitem>
<listitem>can be deployed as a standalone server or an embedded database with a very small footprint
(~700k jar).
</listitem>
<listitem>has a simple and convenient <ulink url="http://api.neo4j.org/">API</ulink>.
</listitem>
</itemizedlist>
</para>
<para>
In addition, Neo4j includes the usual database features: ACID transactions, durable persistence, concurrency control, transaction recovery, high availability and everything else youd expect from an enterprise-strength database. Neo4j is released under a dual free software/commercial license model.</para>
<section>
<title>What is a graph database?</title>
<para>A graph database is a storage engine that is specialized in storing and retrieving vast networks of data. It efficiently stores nodes and relationship and allows high performance traversal of those structures. With property graphs it is possible to add an arbitrary number of properties to nodes
and relationships which can be used directly or during traversals.</para>
</section>
In addition, Neo4j includes the usual database features: ACID transactions, durable persistence,
concurrency control, transaction recovery, high availability and everything else youd expect from an
enterprise database. Neo4j is released under a dual free software/commercial license model.</para>
<section>
<title>What is a graph database?</title>
<para>A graph database is a storage engine that is specialized in storing and retrieving vast networks of
data. It efficiently stores nodes and relationship and allows high performance traversal of those
structures. With property graphs it is possible to add an arbitrary number of properties to nodes
and relationships.</para>
</section>
<section>
<title>GraphDatabaseService</title>
<para>The interface org.neo4j.graphdb.GraphDatabaseService provides access to the storage engine. Its features include creating and retrieving Nodes and Relationships, managing indexes, via an IndexManager, database lifecycle callbacks, transation management and more.

View File

@@ -1,559 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="programming-model">
<title>Programming model for Spring Data Graph</title>
<para>This chapter covers the fundamentals of the programming model behind Spring Data Graph. It discusses the AspectJ features used and the annotations
provided by Spring Data Graph and how to use them.
Examples for this section are taken from the imdb project of <ulink url="http://github.com/SpringSource/spring-data-graph-examples">Spring Data Graph examples</ulink>.
</para>
<section>
<title>Overview of the AspectJ support</title>
<para>Behind the scenes Spring Data Graph leverages AspectJ aspects to modify the behavior of simple POJO entities to be
able to be backed by a graph store. Each entity is backed by a node that holds its properties and
relationships to other entities. AspectJ is used to intercept field access and to reroute it to the backing
state (either its properties or relationships). For relationship entities the fields are similarly mapped to
properties. There are two specially annotated fields for the start and the end node of the relationship.
</para>
<para>
The aspect introduces some internal fields and some public methods to the entities for accessing the backing state via <code>getPersistentState()</code> and creating relationships with <code>relateTo</code> and retrieving relationship entities via <code>getRelationshipTo</code>. It also introduces finder methods like <code>find(Class&lt;? extends NodeEntity&gt;, TraversalDescription)</code> and equals and hashCode delegation.
</para>
<para>
Spring Data Graph internally uses an abstraction called EntityState that the field access and instantiation advices of the aspect delegate to, keeping the aspect code very small and focused to the pointcuts and delegation code. The EntityState then uses a number of FieldAccessor factories to create a FieldAccessor instance per field that does the specific handling needed for the concrete field.
</para>
</section>
<section>
<title>Using annotations to define POJO entities and relationships</title>
<para>Entities are declared using the <code>@NodeEntity</code> annotation. Relationship entities use the <code>@RelationshipEntity</code> annotation.</para>
<section>
<title>Entities with @NodeEntity</title>
<para>The <code>@NodeEntity</code> annotation is used to declare a POJO entity to be backed by a node in the graph store. Simple fields on the entity
are mapped by default to properties of the node. Object references to other NodeEntities (whether single
or Collection) are mapped via relationships. If the annotation parameter <code>useShortNames</code>
is set to false, the properties and relationship names used will be prepended with the class name of the
entity. If the parameter <code>fullIndex</code> is set to true, all fields of the entity will be indexed. If the
<code>partial</code> parameter is set to true, this entity takes part in a cross-store setting where only
the parts of the entity not handled by JPA will be mapped to the graph store.
</para>
<para>Entity fields can be annotated with @GraphProperty, @RelatedTo, @RelatedToVia, @Indexed and @GraphId</para>
<programlisting language="java" ><![CDATA[
@NodeEntity
public class Movie {
String title;
}
]]></programlisting>
</section>
<section>
<title>RelationshipEntities with @RelationshipEntity</title>
<para>To access the rich data model of graph relationships, POJOs can also be annotated with
@RelationshipEntity. Relationship entities can't be instantiated directly but are rather accessed via
node entities, either by @RelatedToVia fields or by the <code>relateTo</code>
or <code>getRelationshipTo</code> methods.
Relationship entities may contain fields that are mapped to properties and two special fields that are
annotated with @StartNode and @EndNode which point to the start and end node entities respectively. These fields are treated as read only fields.
</para>
<programlisting language="java" ><![CDATA[
@RelationshipEntity
public class Role {
@StartNode
private Actor actor;
@EndNode
private Movie movie;
}
]]></programlisting>
</section>
<section>
<title>Fields with @GraphProperty</title>
<para>It is not necessary to annotate fields as they are persisted by default; all fields that contain primitive values are persisted directly to the graph. All fields
convertible to String using the Spring conversion services will be stored as a string. Transient fields are not persisted.
This annotation is mainly used for cross-store persistence. </para>
</section>
<section>
<title>Fields with @RelatedTo pointing to other NodeEntities</title>
<para>
Relationships to other NodeEntities are mapped to graph relationships. Those can either be single
relationships (1:1) or multiple relationships (1:n). In most cases single relationships to other
node entities don't have to be annotated as Spring Data Graph can extract all necessary information from the field
using reflection. In the case of
multiple relationships, the <code>elementClass</code> parameter of @RelatedTo must be specified because of type erasure.
The <code>direction</code> (default OUTGOING) and <code>type</code>
(inferred from field name) parameters of the annotation are optional.
</para>
<para>Relationships to single node entities are created when setting the field and deleted when setting it to null. For multi-relationships the field provides a managed collection (Set) that handles addition and removal of node entities and reflects those in the graph relationships.</para>
<programlisting language="java" ><![CDATA[
@NodeEntity
public class Movie {
private Actor topActor;
}
@NodeEntity
public class Person {
@RelatedTo(type = "topActor", direction = Direction.INCOMING)
private Movie wasTopActorIn;
}
@NodeEntity
public class Actor {
@RelatedTo(type = "ACTS_IN", elementClass = Movie.class)
private Set<Movie> movies;
}
]]></programlisting>
</section>
<section>
<title>Fields with @RelatedToVia pointing to RelationshipEntities</title>
<para>To provide easy programmatic access to the richer relationship entities of the data model a different
annotation @RelatedToVia can be declared on fields of Iterables of the relationship entity type. These
Iterables then provide read only access to instances of the entity that backs the relationship of this
relationship type. Those instances are initialized with the properties of the relationship and the start
and end node.
</para>
<programlisting language="java" ><![CDATA[
@NodeEntity
public class Actor {
@RelatedToVia(type = "ACTS_IN", elementClass = Role.class)
private Iterable<Role> roles;
}
]]></programlisting>
</section>
<section>
<title>@StartNode</title>
<para>Annotation for the start node of a relationship entity, read only.</para>
</section>
<section>
<title>@EndNode</title>
<para>Annotation for the end node of a relationship entity, read only.</para>
</section>
<section>
<title>@Indexed</title>
<para>The @Indexed annotation can be declared on fields that are intended to be indexed by the Neo4j
IndexManager,
triggered by value modification.
The resulting index can be used to later retrieve nodes or relationships that contain a certain property
value (for example a name). Often an index is used to establish the start node for a traversal.
Indexes are accessed by a Finder for a particular NodeEntity or RelationshipEntity, created via a FinderFactory.
</para>
<para>
GraphDatabaseContext exposes the
indexes for Nodes and Relationships. Indexes can
be named, for instance to keep separate domain concepts in separate indexes. That's why it is possible
to specifiy an index name with
the @Indexed annotation. It can also be specified at the entity level, this name is then the default
index name for
all fields of the entity. If no index name is specified, it defaults to the one configured with Neo4j
("node" and "relationship").
</para>
</section>
<section>
<title>@GraphTraversal</title>
<para>The @GraphTraversal annotation leverages the delegation infrastructure used by the Spring Data Graph aspects.
It provides dynamic fields
which, when accessed, return an Iterable of NodeEntities that are the result of a traversal starting at the
current NodeEntity.
The TraversalDescription used for this is created by a TraversalDescriptionBuilder whose class is
referred to by the
<code>traversalBuilder</code>
attribute of the annotation. The class of the expected NodeEntities is provided with the
<code>elementClass</code>
attribute.
</para>
</section>
</section>
<section>
<title>Finding Nodes with Finders</title>
<para>Spring Data Graph also comes with a type bound Repository-like
Finder implementation that provides methods for locating nodes
and relationships:
<itemizedlist>
<listitem><para>using direct access <code>findById(id)</code> , </para></listitem>
<listitem><para>iterating over all nodes of a node entity type (findAll), </para></listitem>
<listitem><para>counting the instances of a node entity type (count), </para></listitem>
<listitem><para>iterating over all indexed instances with a certain property value (findAllByPropertyValue), </para></listitem>
<listitem><para>getting a single instance with a certain property value (findByPropertyValue), </para></listitem>
<listitem><para>iterating over all indexed instances within a certain numerical range (inclusive) (findAllByRange), </para></listitem>
<listitem><para>iterating over a traversal result (findAllByTraversal). </para></listitem>
</itemizedlist>
The Finder instances are created via a FinderFactory to be bound to a
concrete node or relationship entity class.
The FinderFactory is created in the Spring context and can be
injected.
<programlisting language="java" ><![CDATA[
NodeFinder<Person> finder = finderFactory.createNodeEntityFinder(Person.class);
Person dave=finder.findById(123);
int people = finder.count();
Person mark = finder.findByPropertyValue("name", "mark");
Iterable<Person> devs = finder.findAllByProperyValue("occupation","developer");
Iterable<Person> davesFriends = finder.findAllByTraversal(dave,
Traversal.description().pruneAfterDepth(1)
.relationships(KNOWS).filter(returnAllButStartNode()));
]]></programlisting>
</para>
</section>
<section>
<title>Representing Java Types via NodeTypeStrategy</title>
<para>
There are several ways to represent the Java type hierarchy of the data model in the graph. In general for all node and relationship
entities type information is needed to perform certain repository operations. That's why the hierarchy up to <code>java.lang.Object</code> of all
these classes will be persisted in the graph. Implementations of NodeTypeStrategy take care of persisting this information on entity instance
creation. They also provide the repository methods that use this type information to perform their operations like findAll, count etc.
</para>
<para>
The current implementation uses nodes to represent the Java type hierarchy which are connected via SUBCLASS_OF relationships to their superclass
nodes and via INSTANCE_OF relationships to the concrete node entity instance node.
</para>
<para>
An alternative approach could use indexing operations to perform the same functionality. Or one could skip the NodeTypeStrategy altogether if no
strict checks on type conformity are needed, which would allow for a much more flexible data model.
</para>
</section>
<section>
<title>Methods added to Entity Classes</title>
<para>
The node and relationship aspects introduce (via ITD - inter type declaration) several methods to the entities that
make common tasks easier. Unfortunately these methods are not generified yet, so the
results have to be casted to the correct return type.
<variablelist>
<varlistentry>
<term>accessing node and relationship ids</term>
<listitem>
<para><code>nodeEntity.getNodeId() and relationshipEntity.getRelationshipId()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>accessing the node or relationship backing the entity</term>
<listitem>
<para><code>entity.getPersistentState()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>equals and hashcode are delegated to the underlying state</term>
<listitem>
<para><code>entity.equals() and entity.hashCode()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>creating relationships to a target node entity</term>
<listitem>
<para><code>nodeEntity.relateTo(targetEntity, relationshipClass, relationshipType)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>retrieving a single relationship</term>
<listitem>
<para><code>nodeEntity.getRelationshipTo(targetEnttiy, relationshipClass, relationshipType)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>removing a single relationship</term>
<listitem>
<para><code>nodeEntity.removeRelationshipTo(targetEntity, relationshipType)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>remove the node entity, its relationship and index entries</term>
<listitem>
<para><code>entity.remove()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>projecting to a different target type</term>
<listitem>
<para><code>entity.projectTo(targetClass)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>traversing, starting at the current node</term>
<listitem>
<para><code>nodeEntity.findAllByTraversal(targetType, traversalDescription)</code></para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section>
<title>Dynamic Typing - Projection to unrelated, fitting types</title>
<para>
As the underlying data model of a graph database doesn't imply and enforce strict type constraints like a relational
model does, it offers much more flexibility on how to model your domain classes and which of those to use in different
contexts.
</para>
<para>
For instance an order can be used in these contexts: customer, procurement, logistics, billing, fulfillment and many more.
Each of those contexts requires its distinct set of attributes and operations. As Java doesn't support mixins one would put
the sum of all of those into the entity class and thereby making it very big, brittle and hard to understand.
Being able to take a basic order and project it to a different (not related in the inheritance hierarchy or even an interface)
order type that is valid in the current context and only offers the attributes and methods needed here would be very benefitial.
</para>
<para>Spring Data Graph offers initial support for projecting node and relationship entities to different target types.
All instances of this projected entity share the same backing node or relationship, so data changes are reflected
immediately.
</para>
<para>
This could for instance also be used to handle nodes of a traversal with a unified (simpler) type (e.g. for
reporting or auditing) and only project them to a concrete, more functional target type when the business
logic requires it.
</para>
<programlisting language="java" ><![CDATA[
// not related to Person at all
@NodeEntity
class Trainee {
String name;
@RelatedTo(elementClass=Training.class);
Set<Training> trainings;
}
for (Person person : finder.findAllByProperyValue("occupation","developer")) {
Developer developer=person.projectTo(Developer.class)
if (developer.isJavaDeveloper()) {
trainInSpringData(developer.projectTo(Trainee.class));
}
}
]]></programlisting>
</section>
<section>
<title>Neo4jTemplate</title>
<para>The <code>Neo4jTemplate</code> offers the convenient API of Spring templates for the Neo4j graph database.
There are methods for creating nodes and relationships that automatically set provided properties and optionally
index certain fields. Other methods ( <code>index</code> , <code>autoindex</code>) will index them.
</para><para>
For the querying operations Neo4jTemplate unifies the result with the <code>Path</code> abstraction that comes from Neo4j.
Much like a resultset a path contains <code>nodes()</code> and <code>relationships()
</code> starting at a <code>startNode()</code> and
ending with a <code>endNode()</code>, the <code>lastRelationship()</code> is also available separately.
The <code>Path</code> abstraction also wraps results that contain just nodes or relationships.
Using implementations of <code>PathMapper&lt;T&gt;</code> and <code>PathMapper.WithoutResult</code> (comparable with <code>RowMapper</code> and
<code>RowCallbackHandler</code>) the paths can be converted to Java objects.
</para><para>
Query methods either take a field / value combination to look for exact matches in the index or a lucene query
object or string to handle more complex queries.
</para><para>
Traversal methods are the bread and butter of graph operations. As such, they are fully supported in the <code>Neo4jTemplate</code>.
The <code>traverseNext</code> method traverses to the direct neighbours of the start node filtering the relationships according
to its parameters.
</para><para>
The <code>traverse</code> method covers the full fledged traversal operation that takes a powerful <code>TraversalDescription</code>
(most probably built from the <code>Traversal.description()</code> DSL) and runs it from the start node. Each path that is returned
via the traversal is passed to the <code>PathMapper</code> to be processed accordingly.
</para><para>
The <code>Neo4jTemplate</code> provides configurable implicit transactions for all its methods. By default it creates a transaction
for each call (which is a no-op if there is already a transaction running). If you call the constructor
with the <code>useExplicitTransactions</code> parameter set to true, it won't create any transactions so you have to
provide them using @Transactional or the TransactionTemplate.
</para>
<programlisting language="java" ><![CDATA[
Neo4jOperations neo = new Neo4jTemplate(grapDatabase);
Node michael = neo.createNode(_("name","Michael"),"name");
Node mark = neo.createNode(_("name","Mark"));
Node thomas = neo.createNode(_("name","Thomas"));
neo.createRelationship(mark,thomas, WORKS_WITH, _("project","spring-data"));
neo.index("devs",thomas, "name","Thomas");
neo.autoIndex("devs",mark, "name");
assert "Mark".equals(neo.query("devs","name","Mark",new NodeNamePathMapper()));
]]></programlisting>
</section>
<section>
<title>Indexing</title>
<para>
The Neo4j graph database can use different index providers for exact lookups and fulltext searches. Lucene is used as a index provider implementation. There is support for distinct indexes for nodes and relationships
which can be configured to be of fulltext or exact types.
</para>
<para>
Using the standard Neo4j API, Nodes and Relationships and their indexed field-value combinations
have to be added manually to the appropriate index. When using Spring Data Graph, this task is simplified by eased by applying an <code>@Indexed</code> annotation on entity fields. This will result in updates to the index on
every change. Numerical fields are indexed numerically so that they are available for range queries. All other
fields are indexed with their string representation. The @Indexed annotation can also set the index-name to be used.
If @Indexed annotates the entity class, the index-name for the whole entity is preset to that value. Not providing
index names defaults them to "node" and "relationship" respectively.
</para>
<para>
Query access to the index happens with the Node- and RelationshipFinders that are created via an instance of <code>org.springframework.data.graph.neo4j.finder.FinderFactory</code>.
The methods <code>findByPropertyValue</code> and <code>findAllByPropertyValue</code> work on the exact indexes and return the first or all
matches. To do range queries, use <code>findAllByRange</code> (please note that currently both values are inclusive).
</para>
<programlisting language="java" ><![CDATA[
@NodeEntity
class Person {
@Indexed(indexName = "people")
String name;
// automatically indexed numerically
@Indexed
int age;
}
@NodeEntity
@Indexed(indexName="groups")
class Group {
@Indexed
String name;
@RelatedTo(elementClass = Person.class, type = "people" )
Set<Person> people;
}
NodeFinder<Person> finder = finderFactory.createNodeEntityFinder(Person.class);
// exact finder
Person mark = finder.findByProperyValue("people","name","mark");
// numeric range queries
for (Person middleAgedDeveloper : finder.findAllByRange(null, "age", 20, 40)) {
Developer developer=middleAgedDeveloper.projectTo(Developer.class);
}
]]></programlisting>
<para>
Neo4jTemplate also offers index support, providing auto-indexing for fields at creation time of nodes and relationships.
There is an <code>autoIndex</code> method that can also add indexes for a set of fields in one go.
</para>
<para>
For querying the index, the template offers query-methods that take either the exact match parameters or a query object /
query expression and push the results wrapped uniformly as Paths to the supplied <code>PathMapper</code> to be converted or collected.
</para>
</section>
<section>
<title>Transactions in Spring Data Graph</title>
<para>
Neo4j is a transactional datastore which only allows modifications within transaction boundaries and fullfills the ACID properties.
Reading from the store is also possible outside of transactions.
</para>
<para>Spring Data Graph integrates with transaction managers configured using Spring. The simplest scenario of
just running the graph database uses a SpringTransactionManager provided by the Neo4j kernel to be used
with Spring's JtaTransactionManager.
Note: The explicit XML configuration given below is encoded in the <code>Neo4jConfiguration</code> configuration bean that uses Spring's @Configuration functioanlity. This simplifies the configuration. An example is shown further below.
</para>
<programlisting language="xml" ><![CDATA[
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
<constructor-arg ref="graphDatabaseService"/>
</bean>
</property>
<property name="userTransaction">
<bean class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
<constructor-arg ref="graphDatabaseService"/>
</bean>
</property>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
]]></programlisting>
<para>
For scenarios running multiple transactional resources there are two options.
First of all you can have Neo4j participate in the externally set up transaction manager using the new
SpringProvider by enabling the configuration parameter for your graph database. Either via the spring config
or the configuration file (neo4j.properties).
</para>
<programlisting language="xml" ><![CDATA[
<context:annotation-config />
<context:spring-configured/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean id="jotm" class="org.springframework.data.graph.neo4j.transaction.JotmFactoryBean"/>
</property>
</bean>
<bean class="org.neo4j.kernel.EmbeddedGraphDatabase" destroy-method="shutdown">
<constructor-arg value="target/test-db"/>
<constructor-arg>
<map>
<entry key="tx_manager_impl" value="spring-jta"/>
</map>
</constructor-arg>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
]]></programlisting>
<para>
You can configure a stock XA transaction manager to be used with Neo4j and the other resources (e.g. Atomikos, JOTM,
App-Server-TM). For a bit less secure but fast 1 phase commit best effort, use the implementation coming
with Spring Data Graph (<code>ChainedTransactionManager</code>).
It takes a list of transaction-managers as constructor params and will handle them in order for transaction
start and commit (or rollback) in the reverse order.
</para>
<programlisting language="xml" ><![CDATA[
<bean id="transactionManager" class="org.springframework.data.graph.neo4j
.transaction.ChainedTransactionManager" >
<constructor-arg>
<list>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="jpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
<constructor-arg ref="graphDatabaseService" />
</bean>
</property>
<property name="userTransaction">
<bean class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
<constructor-arg ref="graphDatabaseService" />
</bean>
</property>
</bean>
</list>
</constructor-arg>
</bean>
]]></programlisting>
</section>
<section>
<title>Bean Validation - JSR-303</title>
<para>Spring Data Graph supports property based validation support. So whenever a property is changed, it is
checked against the annotated constraints (.e.g @Min, @Max, @Size, etc).
Validation errors throw a ValidationException. For evaluating the constraints the validation support that comes
with Spring is used. To use it a validator has to be registered with the GraphDatabaseContext, if there is none,
no validation will be performed (any registered Validator or (Local)ValidatorFactoryBean will be used).
</para>
<programlisting language="java" ><![CDATA[
@NodeEntity
class Person {
@Size(min = 3, max = 20)
String name;
@Min(0)
@Max(100)
int age;
}
]]></programlisting>
</section>
<section>
<title>Session handling - attached and detached Entities</title>
<para>
By default newly created node entities are in a detached state. When <code>persist()</code> is called on the entity
it is attached to the graph store and its properties and relationships are persisted as well. Changing an attached
entity inside a transaction will write through the changes to the datastore. Whenever an entity is changed outside
of a transaction it will be considered detached. The changed data is stored in the entity itself and not written
back to the datastore.
</para>
<para>
All entities that are returned by library functions are initially in an attached state. Changing them outside of a
transaction detaches them. For writing the changes back it is necessary to <code>persist()</code> them again.
</para>
<para>
Persisting an entity not only persists that single entity but will traverse its existing and new relationships and
persist the cluster of detached entities that it is part of. The borders of this cluster are formed by attached entities.
The persist operation creates its own, implicit transaction. When it is called withina external transaction it participates
otherwise it is an atomic operation.
</para>
<para>
Please keep in mind that the session handling behaviour is still heavily developed. The defaults and also other
aspects of the behaviour are likely to change in subsequent releases. At the moment there is no support for the creation
of relationships outside of transactions and also more complex operations like creating whole subgraphs is not supported.
</para>
<programlisting language="java" ><![CDATA[
@NodeEntity
class Person {
String name;
}
Person p = new Person().persist();
]]></programlisting>
</section>
</chapter>

View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Using annotations to define POJO entities and relationships</title>
<para>Entities are declared using the <code>@NodeEntity</code> annotation. Relationship entities use the
<code>@RelationshipEntity</code>
annotation.
</para>
<section>
<title>Entities with @NodeEntity</title>
<para>The <code>@NodeEntity</code> annotation is used to declare a POJO entity to be backed by a node in the
graph store. Simple fields on the entity are mapped by default to properties of the node. Object
references to other NodeEntities (whether single or Collection) are mapped via relationships. If
the annotation parameter <code>useShortNames</code> is set to false, the properties and relationship
names used will be prepended with the class name of the entity. If the parameter <code>fullIndex</code>
is set to true, all fields of the entity will be indexed. If the <code>partial</code>
parameter is set to true, this entity takes part in a cross-store setting where only
the parts of the entity not handled by JPA will be mapped to the graph store.
</para>
<para>Entity fields can be annotated with @GraphProperty, @RelatedTo, @RelatedToVia, @Indexed and @GraphId
</para>
<programlisting language="java"><![CDATA[
@NodeEntity
public class Movie {
String title;
}
]]></programlisting>
</section>
<section>
<title>RelationshipEntities with @RelationshipEntity</title>
<para>To access the rich data model of graph relationships, POJOs can also be annotated with
@RelationshipEntity. Relationship entities can't be instantiated directly but are rather accessed via
node entities, either by @RelatedToVia fields or by the <code>relateTo</code> or
<code>getRelationshipTo</code> methods.
Relationship entities may contain fields that are mapped to properties and two special fields that are
annotated with @StartNode and @EndNode which point to the start and end node entities respectively. These
fields are treated as read only fields.
</para>
<programlisting language="java"><![CDATA[
@RelationshipEntity
public class Role {
@StartNode
private Actor actor;
@EndNode
private Movie movie;
}
]]></programlisting>
</section>
<section>
<title>Fields with @GraphProperty</title>
<para>It is not necessary to annotate fields as they are persisted by default; all fields that contain primitive
values are persisted directly to the graph. All fields
convertible to String using the Spring conversion services will be stored as a string. Transient fields are
not persisted.
This annotation is mainly used for cross-store persistence.
</para>
</section>
<section>
<title>Fields with @RelatedTo pointing to other NodeEntities</title>
<para>
Relationships to other NodeEntities are mapped to graph relationships. Those can either be single
relationships (1:1) or multiple relationships (1:n). In most cases single relationships to other
node entities don't have to be annotated as Spring Data Graph can extract all necessary information
from the field using reflection. In the case of multiple relationships, the <code>elementClass</code>
parameter of @RelatedTo must be specified because of type erasure. The <code>direction</code>
(default OUTGOING) and <code>type</code> (inferred from field name) parameters of the annotation are
optional.
</para>
<para>Relationships to single node entities are created when setting the field and deleted when setting it to
null. For multi-relationships the field provides a managed collection (Set) that handles addition and
removal of node entities and reflects those in the graph relationships.
</para>
<programlisting language="java"><![CDATA[
@NodeEntity
public class Movie {
private Actor topActor;
}
@NodeEntity
public class Person {
@RelatedTo(type = "topActor", direction = Direction.INCOMING)
private Movie wasTopActorIn;
}
@NodeEntity
public class Actor {
@RelatedTo(type = "ACTS_IN", elementClass = Movie.class)
private Set<Movie> movies;
}
]]></programlisting>
</section>
<section>
<title>Fields with @RelatedToVia pointing to RelationshipEntities</title>
<para>To provide easy programmatic access to the richer relationship entities of the data model a different
annotation @RelatedToVia can be declared on fields of Iterables of the relationship entity type. These
Iterables then provide read only access to instances of the entity that backs the relationship of this
relationship type. Those instances are initialized with the properties of the relationship and the start
and end node.
</para>
<programlisting language="java"><![CDATA[
@NodeEntity
public class Actor {
@RelatedToVia(type = "ACTS_IN", elementClass = Role.class)
private Iterable<Role> roles;
}
]]></programlisting>
</section>
<section>
<title>@StartNode</title>
<para>Annotation for the start node of a relationship entity, read only.</para>
</section>
<section>
<title>@EndNode</title>
<para>Annotation for the end node of a relationship entity, read only.</para>
</section>
<section>
<title>@Indexed</title>
<para>The @Indexed annotation can be declared on fields that are intended to be indexed by the Neo4j
IndexManager, triggered by value modification.
The resulting index can be used to later retrieve nodes or relationships that contain a certain property
value (for example a name). Often an index is used to establish the start node for a traversal.
Indexes are accessed by a Finder for a particular NodeEntity or RelationshipEntity, created via a
FinderFactory.
</para>
<para>
GraphDatabaseContext exposes the indexes for Nodes and Relationships. Indexes can
be named, for instance to keep separate domain concepts in separate indexes. That's why it is possible
to specifiy an index name with the @Indexed annotation. It can also be specified at the entity level,
this name is then the default index name for all fields of the entity. If no index name is specified,
it defaults to the one configured with Neo4j ("node" and "relationship").
</para>
</section>
<section>
<title>@GraphTraversal</title>
<para>The @GraphTraversal annotation leverages the delegation infrastructure used by the Spring Data Graph
aspects. It provides dynamic fields which, when accessed, return an Iterable of NodeEntities that are
the result of a traversal starting at the current NodeEntity. The TraversalDescription used for this
is created by a TraversalDescriptionBuilder whose class is referred to by the <code>traversalBuilder</code>
attribute of the annotation. The class of the expected NodeEntities is provided with the
<code>elementClass</code> attribute.
</para>
</section>
</section>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Overview of the AspectJ support</title>
<para>Behind the scenes Spring Data Graph leverages AspectJ aspects to modify the behavior of simple POJO entities
to be
able to be backed by a graph store. Each entity is backed by a node that holds its properties and
relationships to other entities. AspectJ is used to intercept field access and to reroute it to the backing
state (either its properties or relationships). For relationship entities the fields are similarly mapped to
properties. There are two specially annotated fields for the start and the end node of the relationship.
</para>
<para>
The aspect introduces some internal fields and some public methods to the entities for accessing the backing
state via <code>getPersistentState()</code> and creating relationships with <code>relateTo</code>
and retrieving relationship entities via<code>getRelationshipTo</code>. It also introduces finder methods like
<code>find(Class&lt;? extends NodeEntity&gt;, TraversalDescription)</code>
and equals and hashCode delegation.
</para>
<para>
Spring Data Graph internally uses an abstraction called EntityState that the field access and instantiation
advices of the aspect delegate to, keeping the aspect code very small and focused to the pointcuts and
delegation code. The EntityState then uses a number of FieldAccessor factories to create a FieldAccessor
instance per field that does the specific handling needed for the concrete field.
</para>
</section>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Session handling - attached and detached entities</title>
<para>
By default newly created node entities are in a detached state. When <code>persist()</code> is called on the
entity it is attached to the graph store and its properties and relationships are persisted as well. Changing
an attached entity inside a transaction will write through the changes to the datastore. Whenever an entity
is changed outside of a transaction it will be considered detached. The changed data is stored in the entity
itself and not written back to the datastore.
</para>
<para>
All entities that are returned by library functions are initially in an attached state. Changing them outside
of a transaction detaches them. For writing the changes back it is necessary to <code>persist()</code> them
again.
</para>
<para>
Persisting an entity not only persists that single entity but will traverse its existing and new relationships
and persist the cluster of detached entities that it is part of. The borders of this cluster are formed by
attached entities. The persist operation creates its own, implicit transaction. When it is called withina
external transaction it participates otherwise it is an atomic operation.
</para>
<para>
Please keep in mind that the session handling behaviour is still heavily developed. The defaults and also
other aspects of the behaviour are likely to change in subsequent releases. At the moment there is no support
for the creation of relationships outside of transactions and also more complex operations like creating
whole subgraphs outside of transactions is not supported.
</para>
<programlisting language="java"><![CDATA[
@NodeEntity
class Person {
String name;
}
Person p = new Person().persist();
]]></programlisting>
</section>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Bean Validation - JSR-303</title>
<para>
Spring Data Graph supports property based validation support. So whenever a property is changed, it is
checked against the annotated constraints (.e.g @Min, @Max, @Size, etc).
Validation errors throw a ValidationException. For evaluating the constraints the validation support that
comes with Spring is used. To use it a validator has to be registered with the GraphDatabaseContext, if there
is none, no validation will be performed (any registered Validator or (Local)ValidatorFactoryBean will be
used).
</para>
<programlisting language="java"><![CDATA[
@NodeEntity
class Person {
@Size(min = 3, max = 20)
String name;
@Min(0)
@Max(100)
int age;
}
]]></programlisting>
</section>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Finding nodes with finders</title>
<para>Spring Data Graph also comes with a type bound Repository-like
Finder implementation that provides methods for locating nodes
and relationships:
<itemizedlist>
<listitem>
<para>using direct access <code>findById(id)</code>,</para>
</listitem>
<listitem>
<para>iterating over all nodes of a node entity type (findAll),</para>
</listitem>
<listitem>
<para>counting the instances of a node entity type (count),</para>
</listitem>
<listitem>
<para>iterating over all indexed instances with a certain property value (findAllByPropertyValue),
</para>
</listitem>
<listitem>
<para>getting a single instance with a certain property value (findByPropertyValue),</para>
</listitem>
<listitem>
<para>iterating over all indexed instances within a certain numerical range (inclusive)
(findAllByRange),
</para>
</listitem>
<listitem>
<para>iterating over a traversal result (findAllByTraversal).</para>
</listitem>
</itemizedlist>
The Finder instances are created via a FinderFactory to be bound to a
concrete node or relationship entity class.
The FinderFactory is created in the Spring context and can be
injected.
<programlisting language="java"><![CDATA[
NodeFinder<Person> finder = finderFactory.createNodeEntityFinder(Person.class);
Person dave=finder.findById(123);
int people = finder.count();
Person mark = finder.findByPropertyValue("name", "mark");
Iterable<Person> devs = finder.findAllByProperyValue("occupation","developer");
Iterable<Person> davesFriends = finder.findAllByTraversal(dave,
Traversal.description().pruneAfterDepth(1)
.relationships(KNOWS).filter(returnAllButStartNode()));
]]></programlisting>
</para>
</section>

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section id="reference:programming-model:indexing">
<title>Indexing</title>
<para>
The Neo4j graph database can use different index providers for exact lookups and fulltext searches. Lucene is
used as a index provider implementation. There is support for distinct indexes for nodes and relationships
which can be configured to be of fulltext or exact types.
</para>
<para>
Using the standard Neo4j API, Nodes and Relationships and their indexed field-value combinations
have to be added manually to the appropriate index. When using Spring Data Graph, this task is simplified by
eased by applying an <code>@Indexed</code> annotation on entity fields. This will result in updates to the
index on every change. Numerical fields are indexed numerically so that they are available for range queries.
All other fields are indexed with their string representation. The @Indexed annotation can also set the
index-name to be used. If @Indexed annotates the entity class, the index-name for the whole entity is preset
to that value. Not providing index names defaults them to "node" and "relationship" respectively.
</para>
<para>
Query access to the index happens with the Node- and RelationshipFinders that are created via an instance of
<code>org.springframework.data.graph.neo4j.finder.FinderFactory</code>. The methods
<code>findByPropertyValue</code> and <code>findAllByPropertyValue</code> work on the exact indexes and
return the first or all matches. To do range queries, use <code>findAllByRange</code> (please note that
currently both values are inclusive).
</para>
<programlisting language="java"><![CDATA[
@NodeEntity
class Person {
@Indexed(indexName = "people")
String name;
// automatically indexed numerically
@Indexed
int age;
}
@NodeEntity
@Indexed(indexName="groups")
class Group {
@Indexed
String name;
@RelatedTo(elementClass = Person.class, type = "people" )
Set<Person> people;
}
NodeFinder<Person> finder = finderFactory.createNodeEntityFinder(Person.class);
// exact finder
Person mark = finder.findByProperyValue("people","name","mark");
// numeric range queries
for (Person middleAgedDeveloper : finder.findAllByRange(null, "age", 20, 40)) {
Developer developer=middleAgedDeveloper.projectTo(Developer.class);
}
]]></programlisting>
<para>
Neo4jTemplate also offers index support, providing auto-indexing for fields at creation time of nodes and
relationships. There is an <code>autoIndex</code> method that can also add indexes for a set of fields in one
go.
</para>
<para>
For querying the index, the template offers query-methods that take either the exact match parameters or a query
object / query expression and push the results wrapped uniformly as Paths to the supplied
<code>PathMapper</code> to be converted or collected.
</para>
</section>

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Methods added to entity classes</title>
<para>
The node and relationship aspects introduce (via ITD - inter type declaration) several methods to the
entities that make common tasks easier. Unfortunately these methods are not generified yet, so the
results have to be casted to the correct return type.
<variablelist>
<varlistentry>
<term>accessing node and relationship ids</term>
<listitem>
<para><code>nodeEntity.getNodeId() and relationshipEntity.getRelationshipId()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>accessing the node or relationship backing the entity</term>
<listitem>
<para><code>entity.getPersistentState()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>equals and hashcode are delegated to the underlying state</term>
<listitem>
<para><code>entity.equals() and entity.hashCode()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>creating relationships to a target node entity</term>
<listitem>
<para><code>nodeEntity.relateTo(targetEntity, relationshipClass, relationshipType)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>retrieving a single relationship</term>
<listitem>
<para><code>nodeEntity.getRelationshipTo(targetEnttiy, relationshipClass, relationshipType)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>removing a single relationship</term>
<listitem>
<para><code>nodeEntity.removeRelationshipTo(targetEntity, relationshipType)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>remove the node entity, its relationship and index entries</term>
<listitem>
<para><code>entity.remove()</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>projecting to a different target type</term>
<listitem>
<para><code>entity.projectTo(targetClass)</code></para>
</listitem>
</varlistentry>
<varlistentry>
<term>traversing, starting at the current node</term>
<listitem>
<para><code>nodeEntity.findAllByTraversal(targetType, traversalDescription)</code></para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section id="reference:programming-model:neo4jtemplate">
<title>Neo4jTemplate</title>
<para>
The <code>Neo4jTemplate</code> offers the convenient API of Spring templates for the Neo4j graph database.
There are methods for creating nodes and relationships that automatically set provided properties and optionally
index certain fields. Other methods (<code>index</code>, <code>autoindex</code>) will index them.
</para>
<para>
For the querying operations Neo4jTemplate unifies the result with the <code>Path</code> abstraction that
comes from Neo4j. Much like a resultset a path contains <code>nodes()</code> and <code>relationships()</code>
starting at a <code>startNode()</code> and ending with a<code>endNode()</code>, the
<code>lastRelationship()</code> is also available separately. The <code>Path</code> abstraction also wraps
results that contain just nodes or relationships. Using implementations of <code>PathMapper&lt;T&gt;</code>
and <code>PathMapper.WithoutResult</code> (comparable with <code>RowMapper</code> and
<code>RowCallbackHandler</code>) the paths can be converted to Java objects.
</para>
<para>
Query methods either take a field / value combination to look for exact matches in the index or a lucene query
object or string to handle more complex queries.
</para>
<para>
Traversal methods are the bread and butter of graph operations. As such, they are fully supported in the
<code>Neo4jTemplate</code>. The <code>traverseNext</code> method traverses to the direct neighbours of the
start node filtering the relationships according to its parameters.
</para>
<para>
The <code>traverse</code> method covers the full fledged traversal operation that takes a powerful
<code>TraversalDescription</code> (most probably built from the <code>Traversal.description()</code>
DSL) and runs it from the start node. Each path that is returned via the traversal is passed to the
<code>PathMapper</code> to be processed accordingly.
</para>
<para>
The <code>Neo4jTemplate</code> provides configurable implicit transactions for all its methods. By default
it creates a transaction for each call (which is a no-op if there is already a transaction running). If
you call the constructor with the <code>useExplicitTransactions</code> parameter set to true, it won't
create any transactions so you have to provide them using @Transactional or the TransactionTemplate.
</para>
<programlisting language="java"><![CDATA[
Neo4jOperations neo = new Neo4jTemplate(grapDatabase);
Node michael = neo.createNode(_("name","Michael"),"name");
Node mark = neo.createNode(_("name","Mark"));
Node thomas = neo.createNode(_("name","Thomas"));
neo.createRelationship(mark,thomas, WORKS_WITH, _("project","spring-data"));
neo.index("devs",thomas, "name","Thomas");
neo.autoIndex("devs",mark, "name");
assert "Mark".equals(neo.query("devs","name","Mark",new NodeNamePathMapper()));
]]></programlisting>
</section>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Reified types for entities</title>
<para>
There are several ways to represent the Java type hierarchy of the data model in the graph. In general for all
node and relationship entities type information is needed to perform certain repository operations. That's
why the hierarchy up to <code>java.lang.Object</code> of all these classes will be persisted in the graph.
Implementations of NodeTypeStrategy take care of persisting this information on entity instance
creation. They also provide the repository methods that use this type information to perform their operations
like findAll, count etc.
</para>
<para>
The current implementation uses nodes to represent the Java type hierarchy which are connected via SUBCLASS_OF
relationships to their superclass nodes and via INSTANCE_OF relationships to the concrete node entity
instance node.
</para>
<para>
An alternative approach could use indexing operations to perform the same functionality. Or one could skip the
NodeTypeStrategy altogether if no strict checks on type conformity are needed, which would allow for a much
more flexible data model.
</para>
</section>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="programming-model" xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Programming model for Spring Data Graph</title>
<para>
This chapter covers the fundamentals of the programming model behind Spring Data Graph. It discusses the
AspectJ features used and the annotations provided by Spring Data Graph and how to use them.
Examples for this section are taken from the imdb project of
<ulink url="http://github.com/SpringSource/spring-data-graph-examples">Spring Data Graph examples</ulink>.
</para>
<xi:include href="aspectj.xml"/>
<xi:include href="annotations.xml"/>
<xi:include href="indexing.xml"/>
<xi:include href="finders.xml"/>
<xi:include href="transactions.xml"/>
<xi:include href="attachdetach.xml"/>
<xi:include href="nodetypestrategy.xml"/>
<xi:include href="introducedmethods.xml"/>
<xi:include href="projection.xml"/>
<xi:include href="neo4jtemplate.xml"/>
<xi:include href="beanvalidation.xml"/>
</chapter>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Dynamic typing - Projection to unrelated, fitting types</title>
<para>
As the underlying data model of a graph database doesn't imply and enforce strict type constraints like a
relational model does, it offers much more flexibility on how to model your domain classes and which of
those to use in different contexts.
</para>
<para>
For instance an order can be used in these contexts: customer, procurement, logistics, billing, fulfillment
and many more. Each of those contexts requires its distinct set of attributes and operations. As Java
doesn't support mixins one would put the sum of all of those into the entity class and thereby making it
very big, brittle and hard to understand. Being able to take a basic order and project it to a different
(not related in the inheritance hierarchy or even an interface) order type that is valid in the current
context and only offers the attributes and methods needed here would be very benefitial.
</para>
<para>Spring Data Graph offers initial support for projecting node and relationship entities to different target
types. All instances of this projected entity share the same backing node or relationship, so data changes are
reflected immediately.
</para>
<para>
This could for instance also be used to handle nodes of a traversal with a unified (simpler) type (e.g. for
reporting or auditing) and only project them to a concrete, more functional target type when the business
logic requires it.
</para>
<programlisting language="java"><![CDATA[
// not related to Person at all
@NodeEntity
class Trainee {
String name;
@RelatedTo(elementClass=Training.class);
Set<Training> trainings;
}
for (Person person : finder.findAllByProperyValue("occupation","developer")) {
Developer developer = person.projectTo(Developer.class);
if (developer.isJavaDeveloper()) {
trainInSpringData(developer.projectTo(Trainee.class));
}
}
]]></programlisting>
</section>

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Transactions in Spring Data Graph</title>
<para>
Neo4j is a transactional datastore which only allows modifications within transaction boundaries and fullfills
the ACID properties. Reading from the store is also possible outside of transactions.
</para>
<para>Spring Data Graph integrates with transaction managers configured using Spring. The simplest scenario of
just running the graph database uses a SpringTransactionManager provided by the Neo4j kernel to be used
with Spring's JtaTransactionManager.
Note: The explicit XML configuration given below is encoded in the <code>Neo4jConfiguration</code>
configuration bean that uses Spring's @Configuration functioanlity. This simplifies the configuration.
An example is shown further below.
</para>
<programlisting language="xml"><![CDATA[
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
<constructor-arg ref="graphDatabaseService"/>
</bean>
</property>
<property name="userTransaction">
<bean class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
<constructor-arg ref="graphDatabaseService"/>
</bean>
</property>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
]]></programlisting>
<para>
For scenarios running multiple transactional resources there are two options.
First of all you can have Neo4j participate in the externally set up transaction manager using the new
SpringProvider by enabling the configuration parameter for your graph database. Either via the spring config
or the configuration file (neo4j.properties).
</para>
<programlisting language="xml"><![CDATA[
<context:annotation-config />
<context:spring-configured/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean id="jotm" class="org.springframework.data.graph.neo4j.transaction.JotmFactoryBean"/>
</property>
</bean>
<bean class="org.neo4j.kernel.EmbeddedGraphDatabase" destroy-method="shutdown">
<constructor-arg value="target/test-db"/>
<constructor-arg>
<map>
<entry key="tx_manager_impl" value="spring-jta"/>
</map>
</constructor-arg>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
]]></programlisting>
<para>
You can configure a stock XA transaction manager to be used with Neo4j and the other resources (e.g. Atomikos,
JOTM, App-Server-TM). For a bit less secure but fast 1 phase commit best effort, use the implementation coming
with Spring Data Graph (<code>ChainedTransactionManager</code>). It takes a list of transaction-managers as
constructor params and will handle them in order for transaction start and commit (or rollback) in the reverse
order.
</para>
<programlisting language="xml"><![CDATA[
<bean id="transactionManager"
class="org.springframework.data.graph.neo4j.transaction.ChainedTransactionManager" >
<constructor-arg>
<list>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="jpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
<constructor-arg ref="graphDatabaseService" />
</bean>
</property>
<property name="userTransaction">
<bean class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
<constructor-arg ref="graphDatabaseService" />
</bean>
</property>
</bean>
</list>
</constructor-arg>
</bean>
]]></programlisting>
</section>