Как создать узел с Neo4jClient в Neo4j v2?

под СУБД Neo4j В1.9.x, я использовал следующий код.

private Category CreateNodeCategory(Category cat)
{
        var node = client.Create(cat,
            new IRelationshipAllowingParticipantNode<Category>[0],
            new[]
            {
                new IndexEntry(NeoConst.IDX_Category)
                {
                    { NeoConst.PRP_Name, cat.Name },
                    { NeoConst.PRP_Guid, cat.Nguid.ToString() }
                }
            });
        cat.Nid = node.Id;
        client.Update<Category>(node, cat);
        return cat;
}

причина в том, что идентификатор узла был автоматически сгенерирован, и я мог бы использовать его позже для быстрого поиска, запуска битов в других запросах и т. д. Например:

    private Node<Category> CategoryGet(long nodeId)
    {
        return client.Get<Category>((NodeReference<Category>)nodeId);
    }

Это позволяет следующее, которое, казалось, хорошо работает.

    public Category CategoryAdd(Category cat)
    {
        cat = CategoryFind(cat);
        if (cat.Nid != 0) { return cat; }
        return CreateNodeCategory(cat);
    }

    public Category CategoryFind(Category cat)
    {
        if (cat.Nid != 0) { return cat; }
        var node = client.Cypher.Start(new { 
    n = Node.ByIndexLookup(NeoConst.IDX_Category, NeoConst.PRP_Name, cat.Name)})
            .Return<Node<Category>>("n")
            .Results.FirstOrDefault();
        if (node != null) { cat = node.Data; }
        return cat;
    }

Теперь cypher Wiki, примеры и вредные привычки рекомендуют использовать .ExecuteWithoutResults () во всех CRUD.

Итак, вопрос У меня есть, как у вас есть значение автоматического приращения для идентификатора узла?

1 ответов


во-первых, для Neo4j 2 и далее, вам всегда нужно начинать с системы отсчета "как бы я это сделал в Cypher?". Тогда, и только тогда, вы беспокоитесь о c#.

теперь, перегоняя ваш вопрос, похоже, ваша основная цель-создать узел, а затем вернуть ссылку на него для дальнейшей работы.

вы можете сделать это в Cypher с:

CREATE (myNode)
RETURN myNode

в C# это будет:

var categoryNode = graphClient.Cypher
    .Create("(category {cat})")
    .WithParams(new { cat })
    .Return(cat => cat.Node<Category>())
    .Results
    .Single();

, это все еще не 100% то, что вы делали в своем оригинале CreateNodeCategory метод. Вы создаете узел в БД, получая для него внутренний идентификатор Neo4j, а затем сохраняете этот идентификатор обратно в тот же узел. В принципе, вы используете Neo4j для генерации автоматически увеличивающихся чисел для вас. Это функциональный, но не очень хороший подход. Я объясню подробнее ...

во-первых, концепция Neo4j даже дает вам идентификатор узла обратно уходит. Это внутренние идентификатор, который на самом деле является смещением файла на диске. Это может измениться. Это низкий уровень. Если вы задумаетесь о SQL на секунду, используете ли вы SQL-запрос, чтобы получить смещение байта файла строки, а затем ссылаться на это для будущих обновлений? A: нет; вы пишете запрос, который находит и управляет строкой все за один удар.

сейчас, я замечаю, что у вас уже есть Nguid свойство на узлах. Почему ты не можешь использовать это как удостоверение? Или если имя всегда уникально, используйте это? (Соответствующие идентификаторы домена всегда предпочтительнее магических чисел.) Если ни один из них не подходит, вы можете посмотреть на проект как создатель снега, чтобы помочь вам.

Далее, нам нужно посмотреть индексацию. Тип индексирования, который вы используете, упоминается в документах 2.0 как "Legacy Indexing" и пропускает некоторые из интересных функций 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();

теперь нам не нужно беспокоиться о том, чтобы вручную обновлять индексы.

мы также можем ввести индекс и уникальное ограничение on 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) делает один удар DB, чтобы найти существующий узел, 2) второй удар DB, чтобы создать новый, 3) Третий удар DB, чтобы обновить идентификатор на нем. Вместо этого вы можете сжать все это в один вызов, используя 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();
}

по сути,

  1. не используйте внутренние идентификаторы Neo4j как способ взломать управление своими собственными идентичностями. (Но они могут освободить некоторую форму автонумерации в будущем. Даже если они это делают, доменные удостоверения, такие как адреса электронной почты или SKUs или коды аэропорта или ... предпочтительны. Вам даже не всегда нужен id: вы можете часто выводить узел на основе его положение на графике.)

  2. как правило, Node<T> исчезнет со временем. Если вы используете его сейчас, вы просто накапливаете устаревший код.

  3. смотреть на этикетки и схемы-индексация. Они сделают вашу жизнь проще.

  4. попробуйте сделать что-то в одном запросе. Это будет намного быстрее.

надеюсь, что это поможет!