如何在Neo4j v2中使用Neo4jClient创建节点?

Che*_*val 9 .net c# neo4j neo4jclient

在Neo4j v1.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;
}
Run Code Online (Sandbox Code Playgroud)

原因是节点ID是自动生成的,我可以稍后使用它来快速查找,在其他查询中启动位等.如下所示:

    private Node<Category> CategoryGet(long nodeId)
    {
        return client.Get<Category>((NodeReference<Category>)nodeId);
    }
Run Code Online (Sandbox Code Playgroud)

这使得以下看起来效果很好.

    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;
    }
Run Code Online (Sandbox Code Playgroud)

现在cypher Wiki,示例和坏习惯建议在所有CRUD中使用.ExecuteWithoutResults().

所以我的问题是你如何获得节点ID的自动增量值?

Tat*_*die 21

首先,对于Neo4j 2及其后,您始终需要从参考框架开始"我将如何在Cypher中执行此操作?".那么,只有这样,你是否担心C#.

现在,提炼您的问题,听起来您的主要目标是创建一个节点,然后返回对它的引用以进行进一步的工作.

你可以在cypher中执行以下操作:

CREATE (myNode)
RETURN myNode
Run Code Online (Sandbox Code Playgroud)

在C#中,这将是:

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

但是,这仍然不是您在原始CreateNodeCategory方法中所做的100%.您正在DB中创建节点,获取Neo4j的内部标识符,然后将该标识符保存回同一节点.基本上,您正在使用Neo4j为您生成自动递增数字.这是功能性的,但不是一个好方法.我会解释更多......

首先,Neo4j甚至为您提供节点ID的概念正在消失.它是一个内部标识符,实际上恰好是磁盘上的文件偏移量.它可以改变.这是低水平.如果您考虑SQL一秒钟,您是否使用SQL查询来获取行的文件字节偏移量,然后引用它以供将来更新?答:不; 您编写一个查询,在一次点击中查找和操作该行.

现在,我注意到你已经Nguid在节点上有了一个属性.为什么你不能用它作为id?或者,如果名称始终是唯一的,请使用它?(域相关ID总是比魔术数字更好.)如果两者都不合适,你可能想看看像SnowMaker这样的项目来帮助你.

接下来,我们需要查看索引.您正在使用的索引类型在2.0文档中称为"Legacy Indexing",并且错过了一些很酷的Neo4j 2.0功能.

对于本答复的其余部分,我将假设您的Category课程如下:

public class Category
{
    public Guid UniqueId { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

让我们从创建带有标签的类别节点开始:

var category = new Category { UnqiueId = Guid.NewGuid(), Name = "Spanners" };
graphClient.Cypher
    .Create("(category:Category {category})")
    .WithParams(new { category })
    .ExecuteWithoutResults();
Run Code Online (Sandbox Code Playgroud)

并且,作为一次性操作,让我们使用标签在任何节点的属性上建立基于模式的索引:NameCategory

graphClient.Cypher
    .Create("INDEX ON :Category(Name)")
    .ExecuteWithoutResults();
Run Code Online (Sandbox Code Playgroud)

现在,我们不必担心手动保持索引是最新的.

我们还可以引入一个索引,唯一约束UniqueId:

graphClient.Cypher
    .Create("CONSTRAINT ON (category:Category) ASSERT category.UniqueId IS UNIQUE")
    .ExecuteWithoutResults();
Run Code Online (Sandbox Code Playgroud)

现在查询非常简单:

graphClient.Cypher
    .Match("(c:Category)")
    .Where((Category c) => c.UniqueId == someGuidVariable)
    .Return(c => c.As<Category>())
    .Results
    .Single();
Run Code Online (Sandbox Code Playgroud)

而不是查找类别节点,然后再做另一个查询,只需一次完成所有操作:

var productsInCategory = graphClient.Cypher
    .Match("(c:Category)<-[:IN_CATEGORY]-(p:Product)")
    .Where((Category c) => c.UniqueId == someGuidVariable)
    .Return(p => p.As<Product>())
    .Results;
Run Code Online (Sandbox Code Playgroud)

如果要更新类别,请同时执行此操作:

graphClient.Cypher
    .Match("(c:Category)")
    .Where((Category c) => c.UniqueId == someGuidVariable)
    .Update("c = {category}")
    .WithParams(new { category })
    .ExecuteWithoutResults();
Run Code Online (Sandbox Code Playgroud)

最后,您的CategoryAdd方法当前1)执行一次数据库命中以查找现有节点,2)执行第二次数据库命中以创建新节点,3)第三次数据库命中以更新其上的ID.相反,您也可以使用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();
}
Run Code Online (Sandbox Code Playgroud)

基本上,

  1. 不要使用Neo4j的内部ID来破解管理自己的身份.(但是他们可能会在未来发布某种形式的自动编号.即使他们这样做,也会优先考虑电子邮件地址或SKU或机场代码或......等域名身份.您甚至不需要一个ID:您通常可以推断出节点基于其在图中的位置.)

  2. 一般来说,Node<T>随着时间的推移会消失.如果你现在使用它,你只是累积遗留代码.

  3. 查看标签和基于模式的索引.它们会让你的生活更轻松.

  4. 在一个查询中尝试并执行操作.它会快得多.

希望有所帮助!