DATAGRAPH-449 Updated docs for 3.0 (mostly for index related functionality)

This commit is contained in:
Nicki Watt
2014-03-16 22:01:35 +00:00
committed by Michael Hunger
parent f4bb615b34
commit 532aeb3189
9 changed files with 261 additions and 72 deletions

View File

@@ -79,7 +79,7 @@ h2. Maven configuration
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.0</version>
<version>1.4</version>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
@@ -107,12 +107,12 @@ h2. Maven configuration
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11.RELEASE</version>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.6.11.RELEASE</version>
<version>1.7.4</version>
</dependency>
</dependencies>
</plugin>

View File

@@ -53,10 +53,17 @@
<maven.test.skip>true</maven.test.skip>
</properties>
</profile>
<profile>
<id>distribute</id>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
</profile>
<profile>
<id>examples</id>
<modules>
<module>spring-data-neo4j-examples/hello-worlds</module>
<module>spring-data-neo4j-examples/hello-worlds-aspects</module>
<module>spring-data-neo4j-examples/imdb</module>
<module>spring-data-neo4j-examples/cineasts</module>
<module>spring-data-neo4j-examples/cineasts-aspects</module>

View File

@@ -164,7 +164,7 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware {
* @return the unique entity of type entityClass (if it exists) otherwise returns null.
*
*/
public <T> T findUniqueEntity(final Class<T> entityClass,String propertyName, Object value) {
/*public <T> T findUniqueEntity(final Class<T> entityClass,String propertyName, Object value) {
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(entityClass);
Neo4jPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(propertyName);
@@ -175,6 +175,7 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware {
}
return (T)getSchemaIndexProvider().findAll(persistentProperty,value).singleOrNull();
}
*/
/**
* @return true if a transaction manager is available and a transaction is currently running

View File

@@ -20,9 +20,12 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.data.neo4j.unique.common.CommonClub;
import org.springframework.data.neo4j.unique.common.CommonUniqueClub;
import org.springframework.data.neo4j.unique.common.CommonUniqueEntityTestBase;
@@ -37,13 +40,20 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:unique-legacy-test-context.xml"})
@Transactional
public class UniqueLegacyIndexBasedEntityTests extends CommonUniqueEntityTestBase {
@Autowired
private Neo4jTemplate neo4jTemplate;
@Autowired
private ClubRepository clubRepository;
@@ -77,6 +87,45 @@ public class UniqueLegacyIndexBasedEntityTests extends CommonUniqueEntityTestBas
assertEquals("Expected same node Ids", club1.getId(),club2.getId());
}
@Test
public void creatingDistinctUniqueEntitiesViaNeo4jTemplateShouldResolveToDifferentEntities() {
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
Map<String, Object> fooParams = new HashMap<String,Object>();
fooParams.put("name","foo");
fooParams.put("description","foo description");
Map<String, Object> barParams = new HashMap<String,Object>();
barParams.put("name","bar");
barParams.put("description","foo description");
Node club1 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
Node club2 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(),"name","bar", barParams, labels);
assertNotEquals("Expected different node Ids", club1.getId(), club2.getId());
assertEquals(2, getUniqueClubRepository().count());
}
@Test
public void creatingTheSameUniqueEntitiesViaNeo4jTemplateShouldResolveToOriginalEntity() {
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
Map<String, Object> fooParams = new HashMap<String,Object>();
fooParams.put("name","foo");
fooParams.put("description","foo description");
Map<String, Object> foo2Params = new HashMap<String,Object>();
foo2Params.put("name","foo");
foo2Params.put("description","bar description"); // Note: description differs but will be discarded
Node club1 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
Node club2 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(),"name","foo", foo2Params, labels);
assertEquals("Expected the same node Ids", club1.getId(), club2.getId());
assertEquals(1, getUniqueClubRepository().count());
assertEquals("foo description", club2.getProperty("description"));
}
@Override
protected CommonClub createNonUniqueClub(String name) {
Club club = new Club();

View File

@@ -20,8 +20,10 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.data.neo4j.unique.common.CommonClub;
import org.springframework.data.neo4j.unique.common.CommonUniqueClub;
import org.springframework.data.neo4j.unique.common.CommonUniqueEntityTestBase;
@@ -36,15 +38,19 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:unique-schema-test-context.xml"})
@Transactional
public class UniqueSchemaBasedEntityTests extends CommonUniqueEntityTestBase {
@Autowired
private Neo4jTemplate neo4jTemplate;
@Autowired
private ClubRepository clubRepository;
@@ -81,6 +87,44 @@ public class UniqueSchemaBasedEntityTests extends CommonUniqueEntityTestBase {
return (CommonUniqueClub)getUniqueClubRepository().findBySchemaPropertyValue(propertyName, value);
}
@Test
public void creatingDistinctUniqueEntitiesViaNeo4jTemplateShouldResolveToDifferentEntities() {
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
Map<String, Object> fooParams = new HashMap<String,Object>();
fooParams.put("name","foo");
fooParams.put("description","foo description");
Map<String, Object> barParams = new HashMap<String,Object>();
barParams.put("name","bar");
barParams.put("description","foo description");
Node club1 = neo4jTemplate.merge(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
Node club2 = neo4jTemplate.merge(UniqueClub.class.getSimpleName(),"name","bar", barParams, labels);
assertNotEquals("Expected different node Ids", club1.getId(), club2.getId());
assertEquals(2, getUniqueClubRepository().count());
}
@Test
public void creatingTheSameUniqueEntitiesViaNeo4jTemplateShouldResolveToOriginalEntity() {
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
Map<String, Object> fooParams = new HashMap<String,Object>();
fooParams.put("name","foo");
fooParams.put("description","foo description");
Map<String, Object> foo2Params = new HashMap<String,Object>();
foo2Params.put("name","foo");
foo2Params.put("description","bar description"); // Note: description differs but will be discarded
Node club1 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
Node club2 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(),"name","foo", foo2Params, labels);
assertEquals("Expected the same node Ids", club1.getId(), club2.getId());
assertEquals(1, getUniqueClubRepository().count());
assertEquals("foo description", club2.getProperty("description"));
}
@Override
protected CommonClub createNonUniqueClub(String name) {
Club club = new Club();

View File

@@ -36,7 +36,7 @@
distributed in print or electronically.
</para>
<para>
Copyright 2010-2011 Neo Technology
Copyright 2010-2014 Neo Technology
</para>
</legalnotice>

View File

@@ -74,16 +74,15 @@
<title>Creating nodes and relationships</title>
<para>
Using the API of GraphDatabaseService, it is easy to create nodes and relate them to each other.
Relationships are typed. Both nodes and relationships can have properties. Property values can be
primitive Java types and Strings, or arrays of both. Node creation and
modification has to happen within a transaction, while reading from the graph store can be
done with or without a transaction.
Relationships are typed and both nodes and relationships can have properties. Property values can be
primitive Java types and Strings, or arrays of both. As of Neo4j 2.0, any operation on a
node or relationship (creation, modification or simply reading) must happen within a transaction.
</para>
<example>
<title>Neo4j usage</title>
<programlisting language="java" ><![CDATA[GraphDatabaseService graphDb = new EmbeddedGraphDatabase( "helloworld" );
Transaction tx = graphDb.beginTx();
try {
<programlisting language="java" ><![CDATA[GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase("helloworld");
try (Transaction tx = graphDb.beginTx()) {
Node firstNode = graphDb.createNode();
firstNode.setProperty( "message", "Hello, " );
Node secondNode = graphDb.createNode();
@@ -93,8 +92,6 @@ try {
DynamicRelationshipType.of("KNOWS") );
relationship.setProperty( "message", "brave Neo4j" );
tx.success();
} finally {
tx.close();
}
]]></programlisting>
</example>
@@ -124,31 +121,40 @@ for (Path position : traversalDescription.traverse(myStartNode)) {
<title>Indexing</title>
<para>
The best way for retrieving start nodes for traversals and queries is by using Neo4j's integrated index
facilities. The <code>GraphDatabaseService</code> provides access to the <code>IndexManager</code> which in turn provides
facilities.
<note>
<para>
As of SDN 3.0 , schema based indexes (i.e. indexes based on labels) are the default, however
the legacy indexing functionality still remains, as there is some functionality (for example full text
searches, range searches) which is not possible/ available yet. It should be noted
that legacy based indexes are deprecated in 3.0 and the intention is to eventually
remove it completely as and when schema based indexes/functionality is fully able to support
existing functionality.
</para>
</note>
The <code>GraphDatabaseService</code> still provides access to the legacy <code>IndexManager</code> which in turn provides
named indexes for nodes and relationships. Both can be indexed with property names and values.
Retrieval is done with query methods on indexes, returning an <code>IndexHits</code> iterator.
</para>
<para>
Spring Data Neo4j provides automatic indexing via the <code>@Indexed</code> annotation, eliminating the need
for manual index management.
Spring Data Neo4j provides automatic indexing via the <code>@Indexed</code> annotation, defaulting to make use
of schema based indexes (aka labels), eliminating the need for manual index management.
</para>
<note><para>
Modifying Neo4j indexes also requires transactions.
</para></note>
<example>
<title>Index usage</title>
<title>Legacy Index usage</title>
<programlisting language="java"><![CDATA[IndexManager indexManager = graphDb.index();
Index<Node> nodeIndex = indexManager.forNodes("a-node-index");
Node node = ...;
Transaction tx = graphDb.beginTx();
try {
try (Transaction tx = graphDb.beginTx()) {
nodeIndex.add(node, "property","value");
tx.success();
} finally {
tx.close();
}
for (Node foundNode : nodeIndex.get("property","value")) {
// found node
try (Transaction tx = graphDb.beginTx()) {
for (Node foundNode : nodeIndex.get("property","value")) {
// found node
}
tx.success();
}
]]></programlisting>
</example>
@@ -164,9 +170,12 @@ for (Node foundNode : nodeIndex.get("property","value")) {
<ulink url="http://video.neo4j.org/ybMbf/screencast-introduction-to-cypher/">Neo4j video site</ulink>.
</para>
<para>
Cypher queries always begin with a <code>start</code> set of nodes. Those can be either expressed by their
IDs or by an index lookup expression. Those start-nodes are then related to other nodes in the
<code>match</code> clause. Start and match clauses can introduce new identifiers for nodes and
As of Neo4 2.0, Cypher queries typically begin with a <code>match</code> clause, although the optional
<code>start</code> clause (only really needed when using legacy indexes) is also still supported.
The <code>match</code> clause can be used to provide a way to pattern match against a starting set of nodes, via their
IDs or label based index lookup, with the legacy <code>start</code> clause providing similar functionality.
These starting patterns or start nodes, are then related to other nodes via additional
<code>match</code> clauses. Start and/or match clauses can introduce new identifiers for nodes and
relationships. In the <code>where</code> clause additional filtering of the result set is applied by evaluating
expressions. The <code>return</code> clause defines which part of the query result will be available.
Aggregation also happens in the return clause by using aggregation functions on some of the values.
@@ -182,7 +191,17 @@ for (Node foundNode : nodeIndex.get("property","value")) {
<example>
<title>Cypher Examples on the Cineasts.net Dataset</title>
<programlisting><![CDATA[
// Actors who played a Matrix movie:
// ----------------------------------------------------------
// schema based (Label) examples
// ----------------------------------------------------------
// TODO - once code has been updated
// ----------------------------------------------------------
// Legacy index based examples
// ----------------------------------------------------------
// Actors who played a Matrix movie :
start movie=node:Movie("title:Matrix*") match movie<-[:ACTS_IN]-actor
return actor.name, actor.birthplace?

View File

@@ -11,18 +11,19 @@
</para>
<para>
<note>
Please not that the lucene based manual indexes are deprecated with Neo4j 2.0 and Spring Data Neo4j 3.0.
The default index is now based on labels and schema indexes. Only for fulltext and spatial indexes the
"legacy" index framework should be used. The related APIs have been deprecated as well.
Please note that the lucene based manual indexes are deprecated with Neo4j 2.0 and Spring Data Neo4j 3.0.
The default index is now based on labels and schema indexes and the related APIs have been deprecated as well.
The "legacy" index framework should only be used for fulltext and spatial indexes which are not currently
supported via schema based indexes.
</note>
</para>
<section>
<title>Label based schema indexes</title>
<title>Schema (Label based) indexes</title>
<para>
Since Neo4j version 2.0 indexes and unique constraints based on labels and properties are supported throughout the
API including cypher. For properties of entities annotated with <code>@Indexed</code> an appropriate schema index
and for <code>@Indexed(unique=true)</code> a constraint is created.
API including cypher. For properties of entities annotated with <code>@Indexed</code>, this defaults to using the schema
based strategy, and an appropriate schema index is created. For <code>@Indexed(unique=true)</code> a constraint is created.
</para>
<para>
Those indexes will be automatically used by cypher queries that are generated for the derived finders and are
@@ -30,28 +31,43 @@
</para>
</section>
<para>
The Neo4j graph database employs different index providers for exact lookups and fulltext
searches. Lucene is the default index provider implementation. Each named index is configured to be
fulltext or exact. There is also a spatial index provider for geo-searches.
</para>
<section>
<title>Legacy indexes</title>
<para>
If you would like to force a property on an entity to rather use the legacy index (instead of the
default schema based index), then you will need to explicitly specify the type as either
<code>@Indexed(indexType = IndexType.SIMPLE)</code> or <code>@Indexed(indexType = IndexType.FULLTEXT)</code>
</para>
<para>
The Neo4j graph database employs different index providers for legacy exact (SIMPLE) lookups and fulltext
searches. Lucene is the default index provider implementation. Each named index is configured to be
fulltext or exact. There is also a spatial index provider for geo-searches.
</para>
</section>
<section>
<title>Exact and numeric index</title>
<para>
When using the standard Neo4j API, nodes and relationships have to be manually indexed with
key-value pairs, typically being the property name and value. When using Spring Data Neo4j,
Prior to Neo4j 2.0, when using the standard Neo4j API, nodes and relationships had to be manually
indexed with key-value pairs, typically being the property name and value. With the introduction
of schemas and labels, indexing now happens automatically for you under the covers.
When using Spring Data Neo4j,
irrespective of whether you are using the newer schema based indexes or legacy indexes,
this task is simplified to just adding an <code>@Indexed</code> annotation on entity fields
by which the entity should be searchable. This will result in automatic updates of the index
by which the entity should be searchable. This will result in automatic updates of the appropriate index
every time an indexed field changes.
</para>
<para>
Numerical fields are indexed numerically so that they are available for range queries. All
Numerical fields are indexed numerically so that they are available for range queries.
<note><para>Automatic numerical range queries are not currently supported for
schema based numeric indexes.</para></note>
All
other fields are indexed with their string representation. If a numeric field should not be
indexed numerically, it is possible to switch it off with <code>@Indexed(numeric=false)</code>.
</para>
<para>
The <code>@Indexed</code> annotation also provides the option of using a custom index name. The default index
The <code>@Indexed</code> annotation also provides the option of using a custom index name (for legacy
indexes). The default index
name is the simple class name of the entity, so that each class typically gets its own index.
It is recommended to not have two entity classes with the same class name, regardless of
package.
@@ -63,28 +79,51 @@
that is provided or of the actual entity instance.
</para>
<para>
The indexes can be queried by using a repository (see
The schema based indexes can be queried by using a repository (see
<xref linkend="reference_programming-model_repositories" />).
The repository is an instance of
<code>org.springframework.data.neo4j.repository.SchemaIndexRepository</code>.
The methods <code>findBySchemaPropertyValue()</code> and <code>findAllBySchemaPropertyValue()</code> work on
the exact indexes and return the first or all matches. Range queries are not supported yet.
</para>
<para>
The legacy indexes can also be queried by using a repository (see
<xref linkend="reference_programming-model_repositories" />).
The repository is still an instance of the deprecated
<code>org.springframework.data.neo4j.repository.IndexRepository</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>
<para>
For providing explicit index names the repository has to extend <code>NamedIndexRepository</code>.
When providing explicit index names (for legacy indexes) the repository has to extend <code>NamedIndexRepository</code>.
This adds the shown methods with another signature that take the index name as first parameter.
</para>
<example>
<title>Indexing entities</title>
<title>Exact (schema based) indexes</title>
<programlisting language="java"><![CDATA[@NodeEntity
class Person {
@Indexed(indexName = "people") String name;
@Indexed String name;
@Indexed int age;
}
GraphRepository<Person> graphRepository = template.repositoryFor(Person.class);
// Exact match, in named index
Person mark = graphRepository.findBySchemaPropertyValue("name", "mark");
]]></programlisting>
</example>
<example>
<title>Exact (legacy) indexes</title>
<programlisting language="java"><![CDATA[@NodeEntity
class Person {
@Indexed(indexName = "people",indexType = IndexType.SIMPLE) String name;
@Indexed(indexType = IndexType.SIMPLE) int age;
}
GraphRepository<Person> graphRepository = template.repositoryFor(Person.class);
// Exact match, in named index
Person mark = graphRepository.findByPropertyValue("people", "name", "mark");
@@ -97,9 +136,10 @@ for (Person middleAgedDeveloper : graphRepository.findAllByRange("age", 20, 40))
</section>
<section>
<title>Fulltext indexes</title>
<title>Fulltext (legacy) indexes</title>
<para>
Spring Data Neo4j also supports fulltext indexes. By default, indexed fields are stored in
Spring Data Neo4j also supports fulltext indexes - currently still only via the legacy
indexes. By default, legacy indexed fields are stored in
an exact lookup index. To have them analyzed and prepared for fulltext search, the
<code>@Indexed</code> annotation has the <code>type</code> attribute which can be set to <code>IndexType.FULLTEXT</code>.
@@ -118,7 +158,7 @@ for (Person middleAgedDeveloper : graphRepository.findAllByRange("age", 20, 40))
<title>Fulltext indexing</title>
<programlisting language="java"><![CDATA[@NodeEntity
class Person {
@Indexed(indexName = "people-search", type=FULLTEXT) String name;
@Indexed(indexName = "people-search", indexType=IndexType.FULLTEXT) String name;
}
GraphRepository<Person> graphRepository =
@@ -130,7 +170,7 @@ Person mark = graphRepository.findAllByQuery("people-search", "name", "ma*");
</para>
<note><para>
Please note that indexes are currently created on demand, so whenever an index that doesn't exist
Please note that the legacy indexes are currently created on demand, so whenever an index that doesn't exist
is requested from a query or get operation it is created. This is subject to change but has
currently the implication that those indexes won't be configured as fulltext which causes
subsequent fulltext updates to those indexes to fail.
@@ -139,30 +179,34 @@ Person mark = graphRepository.findAllByQuery("people-search", "name", "ma*");
<section>
<title>Unique indexes</title>
<para>
Unique indexing with <code>index.putIfAbsent</code> and <code>UniqueFactory</code> was introduced in Neo4j 1.6.
It is also available via the REST API.
In Spring Data Neo4j this is made available via <code>Neo4jTemplate.getOrCreateNode</code> and
<code>Neo4jTemplate.getOrCreateRelationship</code>.
Unique indexing can be applied either via the inbuilt schema (label based) unique constraint for nodes, or,
via the legacy <code>index.putIfAbsent</code> and <code>UniqueFactory</code> code for both nodes and relationships.
In Spring Data Neo4j this is done by setting the <code>unique=true</code> property on the <code>@Indexed</code> annotation.
Methods for programmatically getting and/or creating unique entities is available on the <code>Neo4jTemplate</code> class, namely
<code>getOrCreateNode</code> and <code>getOrCreateRelationship</code> for legacy indexes, and <code>merge</code> for schema based
unique entities.
</para>
<para>In an entity at most one field can be annotated with <code>@Indexed(unique=true)</code> regardless of the index-type used.
The uniqueness will be taken into account when creating the entity by reusing an existing entity if that unique key-combination
already exists. On saving of the field it will be cross-checked against the index and fail with a DataIntegrityViolationException
if the field was changed to an already existing unique value. Null values are no longer allowed for these properties.
already exists. On saving of the field it will be cross-checked against the schema or legacy index and fail with a
DataIntegrityViolationException if the field was changed to an already existing unique value.
Null values are no longer allowed for these properties.
</para>
<para>
<note>
This works for both Node-Entities as well as Relationship-Entities. Relationship-Uniqueness in Neo4j is global so that
This works for both Node-Entities as well as Relationship-Entities (legacy indexes only). Relationship-Uniqueness in Neo4j is global so that
an existing unique instance of this relationship may connect two completely different nodes and might also have a
different type.
</note>
</para>
<para>
<example>
<title>Unique indexing</title>
<title>Unique indexing (Schema Based)</title>
<programlisting language="java"><![CDATA[
// creates or finds a node with the unique index-key-value combination
// creates or finds a node with the unique label-key-value combination
// and initializes it with the properties given
template.getOrCreateNode("users", "login", "mh", map("name","Michael","age",37));
List labels = getTRSLabels(Person.class);
template.merge("Person", "name", "Michael", map("name","Michael","age",37),labels);
@NodeEntity class Person {
@Indexed(unique = true) String name;
@@ -179,6 +223,31 @@ Person thomas = repository.save(new Person("thomas"));
thomas.setName("mark");
repository.save(thomas); // fails with a DataIntegrityViolationException
]]></programlisting>
</example>
<example>
<title>Unique indexing (Legacy Based)</title>
<programlisting language="java"><![CDATA[
// creates or finds a node with the unique index-key-value combination
// and initializes it with the properties given
List labels = getTRSLabels(Person.class);
template.getOrCreateNode("Person", "name", "Michael", map("name","Michael","age",37),labels);
@NodeEntity class Person {
@Indexed(indexType = IndexType.SIMPLE, unique = true) String name;
}
Person mark1 = repository.save(new Person("mark"));
Person mark2 = repository.save(new Person("mark"));
// just one node is created
assertEquals(mark1,mark2);
assertEquals(1, personRepository.count());
Person thomas = repository.save(new Person("thomas"));
thomas.setName("mark");
repository.save(thomas); // fails with a DataIntegrityViolationException
]]></programlisting>
</example>
@@ -186,12 +255,12 @@ repository.save(thomas); // fails with a DataIntegrityViolationException
</section>
<section>
<title>Manual index access</title>
<title>Manual (Legacy) index access</title>
<para>
The index for a domain class is also available from <code>Neo4jTemplate</code> via
The legacy index for a domain class is also available from <code>Neo4jTemplate</code> via
the <code>getIndex()</code> method. The second parameter is optional and takes the index name
if it should not be inferred from the class name. It returns the index implementation that is
provided by Neo4j.
provided by Neo4j. Note: Manual Legacy index access is deprecated in SDN 3.0
</para>
<example>
<title>Manual index retrieval by type and name</title>

View File

@@ -98,13 +98,13 @@
<title>Java-based configuration</title>
<programlisting language="java"><![CDATA[
@Configuration
@EnableNeo4jRepositories(basePackages = "org.springframework.data.neo4j.ref.whatever.repositories")
@EnableNeo4jRepositories(basePackages = "org.example.repositories")
static class Config extends Neo4jConfiguration {
Config() {
// Equivalent of setting basePackage for XML based <neo4j:config base-package=".."/>
// (This will probably move into an/the @EnableNeo4jRepositories in the future)
setBasePackage("org.springframework.data.neo4j.model,org.springframework.data.neo4j.repository.query");
setBasePackage("org.example.domain");
}
@Override