Spring Data Neo4j - repository.save и @Indexed (уникальный = true)
Сегодня я попробовал Spring Data Neo4j, у меня наконец-то все заработалокак-то...
Я использую:
Spring 4.0.2Spring Data Neo4j 3.0.0QueryDSL 3.3.1Neo4j 2.0.1Вот мой конфиг:
@Configuration
@EnableNeo4jRepositories(includeFilters=@Filter(value=GraphRepository.class, type=FilterType.ASSIGNABLE_TYPE))
public class Neo4jConfig extends Neo4jConfiguration {
public Neo4jConfig() {
setBasePackage("my.base.package");
}
@Bean
public GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("/tmp/neo4j");
}
}
Класс моего домена:
@NodeEntity
@QueryEntity
public class User implements Persistable<Long> {
@GraphId private Long id;
public Long getId() { return id; }
@NotNull @NotBlank @Email
@Indexed(unique=true)
private String email;
public String getEmail() { return email; }
void setEmail(String email) { this.email = email; }
@Override
public boolean isNew() {
return id==null;
}
@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) : id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
И мой репозиторий:
interface UserRepository extends GraphRepository<User>, CypherDslRepository<User> {}
Я могу успешно создать пользователя в БД и впоследствии получить его через:
User u = repo.query(
start(allNodes("user"))
.where(toBooleanExpression(QUser.user.email.eq("[email protected]")))
.returns(node("user")), new HashMap<String, Object>())
.singleOrNull();
НО: если я теперь вызываю мой код создания во второй раз, этоне будет бросить исключение из-за@Indexed(unique=true) String email
он просто переопределяет объект в БД.
А ТАКЖЕ: если я попытаюсь создать второйUser
с другим значением электронной почты, старый пользователь получает переопределен.
Создать код так же просто, как:
User u = new User();
u.setEmail("[email protected]");
repo.save(u);
Я также попытался использовать автономную версию Neo4j вместо встроенной, с тем же результатом. В представлении webadmin я вижу, что он создал несколько индексов:
Node Indexes: Relationship Indexes:
User {"type":"exact"} __rel_types__ {"type":"exact"}
lucene lucene
Результаты отладки также говорят мне, что Spring создает индекс:
2014-03-12 21:00:34,176 DEBUG o.s.data.neo4j.support.schema.SchemaIndexProvider: 35 - CREATE CONSTRAINT ON (n:`User`) ASSERT n.`email` IS UNIQUE
2014-03-12 21:00:34,177 DEBUG o.s.data.neo4j.support.query.CypherQueryEngine: 63 - Executing cypher query: CREATE CONSTRAINT ON (n:`User`) ASSERT n.`email` IS UNIQUE params {}
Еще немного отладочной информации:
curl -v http://localhost:7474/db/data/index/node
{
"User" : {
"template" : "http://localhost:7474/db/data/index/node/User/{key}/{value}",
"provider" : "lucene",
"type" : "exact"
}
curl -v http://localhost:7474/db/data/schema/index
[ {
"property_keys" : [ "email" ],
"label" : "User"
} ]
curl -v http://localhost:7474/db/data/schema/constraint
[ {
"property_keys" : [ "email" ],
"label" : "User",
"type" : "UNIQUENESS"
} ]
Я действительно не могу себе представить, что я делаю здесь не так ...
Пожалуйста, помогите мне!
ОБНОВЛЕНИЕ № 1:
Из того, что я видел вAbstractGraphRepository.save
оно используетNeo4jTemplate.save
который говорит:
Stores the given entity in the graph, if the entity is already attached to the graph, the node is updated, otherwise a new node is created.
Поэтому я предполагаю, что он всегда «думает», что моя сущность уже привязана. НоЗачем?
ОБНОВЛЕНИЕ № 2:
Если я захожу в webadmin и делаю просто дважды:
CREATE (n:User {email:'[email protected]'})
Я получаю ошибку. Так что должно быть что-то не так с моим кодом Java или SDN ...
ОБНОВЛЕНИЕ № 3:
Spring Data Neo4j'ssave
Метод делает что-то вродеПОЛУЧИТЬ или СОЗДАТЬ:
User u1 = new User();
u1.setEmail("[email protected]");
repo.save(u1); // creates node with id=0
User u2 = new User();
u2.setEmail("[email protected]");
repo.save(u2); // creates node with id=1
User u3 = new User();
u3.setEmail("[email protected]");
repo.save(u3); // updates and returns node with id=0
Как я могу исправить это поведение? Я хочу исключение.
ОБНОВЛЕНИЕ № 4:
Похоже, я искал это:http://docs.neo4j.org/chunked/stable/rest-api-unique-indexes.html#rest-api-create-a-unique-node-or-return-fail-create
Map<String, Object> prop1 = new HashMap<String, Object>();
prop1.put("email", "[email protected]");
neo4jTemplate.createNodeAs(User.class, prop1);
Map<String, Object> prop2 = new HashMap<String, Object>();
prop2.put("email", "[email protected]");
neo4jTemplate.createNodeAs(User.class, prop2);
Таким образом, все работает как положено, по крайней мере, я получаю исключение:
org.neo4j.rest.graphdb.RestResultException: Node 7 already exists with label User and property "email"=[[email protected]]
Но сейчас я не могу понять, как интегрировать это с хранилищем данных Spring ...