如何在 Neo4j v2 中使用 Neo4jClient 创建节点?
Posted
技术标签:
【中文标题】如何在 Neo4j v2 中使用 Neo4jClient 创建节点?【英文标题】:How to Create a Node with Neo4jClient in Neo4j v2? 【发布时间】:2013-10-23 06:37:37 【问题描述】:在 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;
原因是节点 ID 是自动生成的,我可以稍后使用它进行快速查找、其他查询中的起始位等。如下所示:
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、示例和坏习惯建议在所有 CRUD 中使用 .ExecuteWithoutResults()。
所以我的问题是如何为节点 ID 设置自动增量值?
【问题讨论】:
【参考方案1】:首先,对于 Neo4j 2 及更高版本,您始终需要从参考框架“我如何在 Cypher 中执行此操作?”开始。然后,也只有到那时,你才会担心 C#。
现在,提炼您的问题,听起来您的主要目标是创建一个节点,然后返回对它的引用以进行进一步的工作。
你可以用密码来做到这一点:
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 甚至返回节点 ID 的概念正在消失。它是一个 internal 标识符,实际上恰好是磁盘上的文件偏移量。它可以改变。它是低水平的。如果您考虑一下 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;
让我们从使用label 创建我们的类别节点开始:
var category = new Category UnqiueId = Guid.NewGuid(), Name = "Spanners" ;
graphClient.Cypher
.Create("(category:Category category)")
.WithParams(new category )
.ExecuteWithoutResults();
并且,作为一次性操作,让我们在任何带有Category
标签的节点的Name
属性上建立一个schema-based index:
graphClient.Cypher
.Create("INDEX ON :Category(Name)")
.ExecuteWithoutResults();
现在,我们无需担心手动更新索引。
我们还可以在UniqueId
上引入索引和unique constraint:
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 命中以更新其上的 ID。相反,您也可以使用 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 来破解管理自己的身份。 (但他们将来可能会发布某种形式的自动编号。即使他们这样做了,诸如电子邮件地址或 SKU 或机场代码之类的域身份也是首选的。您甚至并不总是需要 id:您通常可以推断出节点基于其在图中的位置。)
通常,Node<T>
会随着时间的推移而消失。如果你现在使用它,你只是在积累遗留代码。
查看标签和基于模式的索引。它们会让您的生活更轻松。
尝试在一个查询中做事。它会快得多。
希望有帮助!
【讨论】:
我假设代码 graphClient.Client 应该是 graphClient.Cypher。当我尝试类似于“查询很容易......”的查询时,我收到错误 “SyntaxException:不再支持此语法(缺少的属性现在返回为 null)。(第 2 行,第 10 列)\n \"WHERE (o.Name! = p0)\r\"\n ^" 使用 1.0.0.625 或更高版本。另外,我已经修复了上面答案中的错别字。当您将内存中的所有内容直接输入文本框时,就会发生这种情况。 :) 这对你有用吗@Cheval?我花了一些时间写这个答案,所以如果你能将它标记为已接受将不胜感激。 是的,谢谢,这是一个非常详细的答案。我将所需的版本放在您的答案标题中,就像另一个项目一样,我忘记升级它并出错了。 这是我尝试通过 C# cypher quereis 找到创建节点的正确方法时的第一次成功,neo4jclient 文档只有索引创建和关系创建,但没有关于节点的内容。。跨度>以上是关于如何在 Neo4j v2 中使用 Neo4jClient 创建节点?的主要内容,如果未能解决你的问题,请参考以下文章