c# – 如何在Neo4j v2中创建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; } 原因是节点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进行自动增量? 解决方法
首先,对于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(); 但是,这仍然不是您原始CreateNodeCategory方法中的100%.您正在创建DB中的节点,获取Neo4j的内部标识符,然后将该标识符保存回同一个节点.基本上,您正在使用Neo4j为您生成自动递增的数字.这是功能,但不是一个很好的方法.我会解释更多… 首先,Neo4j的概念甚至给你节点id回来已经消失了.这是一个内部标识符,实际上恰好是磁盘上的文件偏移量.它可以改变是低水平如果您再次考虑SQL,您是否使用SQL查询来获取一行的文件字节偏移量,然后参考以供将来更新? A:不你写一个查询,可以在一个命中中找到并操纵该行. 现在,我注意到你已经在节点上有一个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(); 而且,作为一次性操作,让我们建立一个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.相反,您可以使用 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的内部ids作为一种方式来管理自己的身份. (但是他们可能会在以后发布某种形式的自动编号,即使是这样,域名身份如电子邮件地址或SKU或机场代码或…是首选,您甚至不需要一个id:你可以经常推断节点根据其在图中的位置.) 希望有帮助! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |