Во-первых, для Neo4j 2 и выше вам всегда нужно начинать с системы отсчета «как бы я сделал это в Cypher?». Тогда и только тогда вы беспокоитесь о C#.
Теперь, уточняя ваш вопрос, похоже, что ваша основная цель - создать узел, а затем вернуть ссылку на него для дальнейшей работы.
Вы можете сделать это в шифре с помощью:
CREATE (myNode)
RETURN myNode
В С# это будет:
var categoryNode = graphClient.Cypher
.Create("(category {cat})")
.WithParams(new { cat })
.Return(cat => cat.Node<Category>())
.Results
.Single();
Однако это все еще не на 100 % то, что вы делали в исходном методе CreateNodeCategory
. Вы создаете узел в БД, получаете для него внутренний идентификатор Neo4j, а затем сохраняете этот идентификатор обратно в тот же узел. По сути, вы используете Neo4j для генерации автоматически увеличивающихся чисел. Это функциональный, но не очень хороший подход. Я объясню больше...
Во-первых, концепция Neo4j, даже возвращающая вам идентификатор узла, уходит. Это внутренний идентификатор, который фактически представляет собой смещение файла на диске. Это может измениться. Это низкий уровень. Если вы на секунду задумаетесь о SQL, используете ли вы SQL-запрос для получения смещения строки в байтах файла, а затем ссылаетесь на него для будущих обновлений? О: Нет; вы пишете запрос, который находит строку и обрабатывает ее одним нажатием.
Теперь я заметил, что у вас уже есть свойство Nguid
на узлах. Почему вы не можете использовать это как идентификатор? Или, если имя всегда уникально, используйте его? (Идентификаторы, соответствующие домену, всегда предпочтительнее, чем магические числа.) Если ни один из них не подходит, вы можете посмотреть проект, например SnowMaker. чтобы помочь вам.
Далее нам нужно посмотреть на индексацию. Используемый вами тип индексации упоминается в документации версии 2.0 как "Устаревшее индексирование" и упускает некоторые интересные функции Neo4j 2.0.
Для остальной части этого ответа я предполагаю, что ваш класс Category
выглядит следующим образом:
public class Category
{
public Guid UniqueId { get; set; }
public string Name { get; set; }
}
Начнем с создания узла категории с меткой:
var category = new Category { UnqiueId = Guid.NewGuid(), Name = "Spanners" };
graphClient.Cypher
.Create("(category:Category {category})")
.WithParams(new { category })
.ExecuteWithoutResults();
И в качестве разовой операции давайте создадим индекс на основе схемы в свойстве Name
любых узлов с меткой Category
:
graphClient.Cypher
.Create("INDEX ON :Category(Name)")
.ExecuteWithoutResults();
Теперь нам не нужно беспокоиться о ручном обновлении индексов.
Мы также можем ввести индекс и уникальное ограничение для UniqueId
:
graphClient.Cypher
.Create("CONSTRAINT ON (category:Category) ASSERT category.UniqueId IS UNIQUE")
.ExecuteWithoutResults();
Запросить теперь очень просто:
graphClient.Cypher
.Match("(c:Category)")
.Where((Category c) => c.UniqueId == someGuidVariable)
.Return(c => c.As<Category>())
.Results
.Single();
Вместо того, чтобы искать узел категории, чтобы затем выполнить другой запрос, просто сделайте все это за один раз:
var productsInCategory = graphClient.Cypher
.Match("(c:Category)<-[:IN_CATEGORY]-(p:Product)")
.Where((Category c) => c.UniqueId == someGuidVariable)
.Return(p => p.As<Product>())
.Results;
Если вы хотите обновить категорию, сделайте это за один раз:
graphClient.Cypher
.Match("(c:Category)")
.Where((Category c) => c.UniqueId == someGuidVariable)
.Update("c = {category}")
.WithParams(new { category })
.ExecuteWithoutResults();
Наконец, ваш метод CategoryAdd
в настоящее время 1) выполняет одно обращение к БД, чтобы найти существующий узел, 2) второе обращение к БД, чтобы создать новый, 3) третье обращение к БД, чтобы обновить идентификатор на нем. Вместо этого вы можете сжать все это в один вызов, используя MERGE
ключевое слово а>:
public Category GetOrCreateCategoryByName(string name)
{
return graphClient.Cypher
.WithParams(new {
name,
newIdIfRequired = Guid.NewGuid()
})
.Merge("(c:Category { Name = {name})")
.OnCreate("c")
.Set("c.UniqueId = {newIdIfRequired}")
.Return(c => c.As<Category>())
.Results
.Single();
}
В принципе,
Не используйте внутренние идентификаторы Neo4j как способ обойти управление собственной личностью. (Но они могут выпустить некоторую форму автонумерации в будущем. Даже если они это сделают, идентификаторы домена, такие как адреса электронной почты или SKU, или коды аэропортов, или ... предпочтительнее. Вам даже не всегда нужен идентификатор: вы часто можете вывести узел в зависимости от его положения на графике.)
Как правило, Node<T>
со временем исчезает. Если вы используете его сейчас, вы просто накапливаете устаревший код.
Изучите метки и индексацию на основе схемы. Они сделают вашу жизнь проще.
Попробуйте сделать что-то в одном запросе. Это будет намного быстрее.
Надеюсь, это поможет!
person
Tatham Oddie
schedule
23.10.2013