如何创建与Neo4jClient中的一个节点的Neo4j V2?节点、Neo4jClient、Neo4j

2023-09-04 01:38:05 作者:只为迩沉沦

在Neo4j的v1.9.x,我用code以下排序。

Under Neo4j v1.9.x, I used the following sort of code.

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;
}

原因是,节点ID是自动生成的,后来我可以用它来快速浏览一下了,开始在其他查询等类似下面的位:

The reason being that the Node Id was auto generated and I could use it later for a quick look up, start bits in other queries, etc. Like the following:

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

这使得它看起来运行良好以下。

This enables the following which appeared to work well.

    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;
    }

现在的暗号维基,例子和坏习惯,建议使用.ExecuteWithoutResults()在所有的CRUD。

Now the cypher Wiki, examples and bad-habits recommend using the .ExecuteWithoutResults() in all the CRUD.

所以这个问题我是怎么做的,你必须为节点ID的自动增加值?

So the question I have is how do you have an Auto Increment value for the node ID?

推荐答案

一起来,为Neo4j的2起,你总是需要先从参照系我将如何做到这一点的Cypher支架?。然后,只有到那时,你不用担心的C#。

First up, for Neo4j 2 and onwards, you always need to start with the frame of reference "how would I do this in Cypher?". Then, and only then, do you worry about the C#.

现在,蒸馏你的问题,这听起来像你的主要目标是创建一个节点,然后返回一个引用它为今后的工作。

Now, distilling your question, it sounds like your primary goal is to create a node, and then return a reference to it for further work.

您可以用暗号做到这一点:

You can do this in cypher with:

CREATE (myNode)
RETURN myNode

在C#中,这将是:

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

然而,这还不是100%,你在做什么在原始 CreateNodeCategory 方法。要创建的节点在DB,得到的Neo4j的内部识别它,然后保存该标识符回到同一节点。基本上,你正在使用的Neo4j生成自动递增的数字给你。这是功能性的,而不是一个真正的好方法。我将解释更多...

However, this still isn't 100% what you were doing in your original CreateNodeCategory method. You are creating the node in the DB, getting Neo4j's internal identifier for it, then saving that identifier back into the same node. Basically, you're using Neo4j to generate auto-incrementing numbers for you. That's functional, but not really a good approach. I'll explain more ...

一起来,Neo4j的甚至给你回的节点ID的概念会消失。这是一个的的内部的标识符,实际情况是文件在磁盘上的偏移量。它可以改变。它是低电平。如果你想SQL一秒钟,你使用一个SQL查询来获取文件的字节一排的偏移,然后引用该为未来的更新?答:没有;你写的查找和操作都在一击的行。搜索

First up, the concept of Neo4j even giving you the node id back is going away. It's an internal identifier that actually happens to be a file offset on disk. It can change. It is low level. If you think about SQL for a second, do you use a SQL query to get the file byte offset of a row, then reference that for future updates? A: No; you write a query that finds and manipulates the row all in one hit.

现在,我发现你已经在节点上的 Nguid 属性。为什么你不能使用,作为ID?或者,如果这个名字始终是唯一的,使用的? (域相关ID始终preferable到幻数。)如果没有合适,你可能想看看像造雪来帮助你。

Now, I notice that you already have an Nguid property on the nodes. Why can't you use that as the id? Or if the name is always unique, use that? (Domain relevant ids are always preferable to magic numbers.) If neither are appropriate, you might want to look at a project like SnowMaker to help you out.

接下来,我们需要看一下索引。您正在使用被称为在2.0文档的旧索引和索引的类型错过了一些很酷的Neo4j 2.0功能。

Next, we need to look at indexing. The type of indexing that you're using is referred to in the 2.0 docs as "Legacy Indexing" and misses out on some of the cool Neo4j 2.0 features.

有关这个答案的其余部分,我会假设你的类别类看起来是这样的:

For the rest of this answer, I'm going to assume your Category class looks like this:

public class Category
{
    public Guid UniqueId { get; set; }
    public string Name { get; set; }
}

让我们先用标签创造我们的类结点:

Let's start by creating our category node with a label:

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

和,作为一次性操作,让我们建立一个架构为基础的指数在名称类的任何节点属性标签:

And, as a one-time operation, let's establish a schema-based index on the Name property of any nodes with the Category label:

graphClient.Cypher
    .Create("INDEX ON :Category(Name)")
    .ExecuteWithoutResults();

现在,我们不需要担心手工保持索引是最新的。

Now, we don't need to worry about manually keeping indexes up to date.

我们还可以引入一个索引,唯一约束中的唯一ID

We can also introduce an index and unique constraint on UniqueId:

graphClient.Cypher
    .Create("CONSTRAINT ON (category:Category) ASSERT category.UniqueId IS UNIQUE")
    .ExecuteWithoutResults();

查询变得非常简单:

Querying is now very easy:

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

而不是找了一类节点,到然后做另一个查询,只是做这一切一气呵成:

Rather than looking up a category node, to then do another query, just do it all in one go:

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

如果要更新一个类别,这样做,在一个去和:

If you want to update a category, do that in one go as well:

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命中更新ID就可以了。相反,你可以COM preSS这一切到一个呼叫也使用 合并关键字:

Finally, your CategoryAdd method currently 1) does one DB hit to find an existing node, 2) a second DB hit to create a new one, 3) a third DB hit to update the ID on it. Instead, you can compress all of this to a single call too using the MERGE keyword:

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的内部ID,以此来破解围绕管理自己的身份。 (但是,他们可能在未来释放某种形式的自动编号的。即使他们这样做,如电子邮件地址或单品或机场codeS域的身份或...是preferred,你甚至不总是需要一个id :基于其在图中的位置,你通常可以推断出一个节点)

Don't use Neo4j's internal ids as a way to hack around managing your own identities. (But they may release some form of autonumbering in the future. Even if they do, domain identities like email addresses or SKUs or airport codes or ... are preferred. You don't even always need an id: you can often infer a node based on its position in the graph.)

一般情况下,节点&lt; T&GT; 会随着时间消失。如果你现在使用它,你只是累积遗留code。

Generally, Node<T> will disappear over time. If you use it now, you're just accruing legacy code.

。看看标签和模式的索引。他们将让您的生活更轻松。

Look into labels and schema-based indexing. They will make your life easier.

试着做的事情在一个查询。这将是快多了。

Try and do things in the one query. It will be much faster.

希望帮助!

 
精彩推荐