2013-10-23 9 views
9

Unter Neo4j v1.9.x verwendete ich die folgende Art von Code.Wie erstelle ich einen Knoten mit Neo4jClient in Neo4j v2?

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

Das ist Grund dafür, dass der Knoten-ID wurde automatisch generiert und ich konnte es später für einen schnellen Blick nach oben verwenden, starte Bits in anderen Abfragen usw. wie folgt aus:

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

Dies ermöglicht das Folgende schien gut zu funktionieren.

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

Nun ist die Chiffre Wiki, Beispiele und schlecht-Gewohnheiten empfehlen .ExecuteWithoutResults mit() in allen CRUD.

Also die Frage, die ich habe, ist, wie haben Sie einen Auto Increment-Wert für die Node-ID?

Antwort

20

Zuerst, für Neo4j 2 und höher, müssen Sie immer mit dem Referenzrahmen beginnen "wie würde ich das in Cypher tun?". Dann und nur dann sorgen Sie sich um die C#.

Nun, Ihre Frage zu destillieren, klingt wie Ihr primäres Ziel ist es, einen Knoten zu erstellen, und dann einen Verweis darauf für die weitere Arbeit zurückgeben.

Sie können dies mit in Chiffre tun:

CREATE (myNode) 
RETURN myNode 

In C#, dies wäre:

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

jedoch, das ist immer noch nicht zu 100%, was Sie in taten Ihre Original CreateNodeCategory Methode. Sie erstellen den Knoten in der Datenbank, erhalten die interne Kennung von Neo4j und speichern diese Kennung dann wieder im selben Knoten. Im Grunde verwenden Sie Neo4j, um automatisch inkrementierende Zahlen für Sie zu generieren. Das ist funktional, aber nicht wirklich ein guter Ansatz. Ich werde mehr erklären ...

Zuerst, das Konzept von Neo4j sogar gibt Ihnen die Node-ID zurück ist weg. Es ist ein interner Bezeichner, der tatsächlich ein Datei-Offset auf der Festplatte ist. Es kann sich ändern. Es ist ein niedriges Niveau. Wenn Sie eine Sekunde über SQL nachdenken, verwenden Sie eine SQL-Abfrage, um den Dateibyte-Offset einer Zeile abzurufen, und verweisen Sie dann für zukünftige Aktualisierungen darauf? A: Nein; Sie schreiben eine Abfrage, die die Zeile in einem Treffer findet und manipuliert.

Jetzt merke ich, dass Sie bereits eine Nguid Eigenschaft auf den Knoten haben. Warum kannst du das nicht als ID benutzen? Oder wenn der Name immer eindeutig ist, benutze das? (Domain-relevante IDs sind immer magischen Zahlen vorzuziehen.) Wenn beides nicht angemessen ist, möchten Sie vielleicht ein Projekt wie SnowMaker betrachten, um Ihnen zu helfen.

Als nächstes müssen wir uns die Indizierung ansehen. Die Art der Indizierung, die Sie verwenden, wird in der 2.0-Dokumentation als "Legacy Indexing" bezeichnet und verpasst einige der coolen Neo4j 2.0-Funktionen.

Für den Rest dieser Antwort, ich Ihre Category Klasse zu übernehmen werde sieht wie folgt aus:

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

die mit einem label indem unserer Kategorie Knoten Beginnen wir:

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

Und , als eine einmalige Operation, lassen Sie uns eine schema-based index auf der Name Eigenschaft aller Knoten mit dem Category Label:

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

Jetzt müssen wir uns nicht darum sorgen, Indizes manuell auf dem neuesten Stand zu halten.

Wir können auch einen Index und unique constraint auf UniqueId vorstellen:

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

Querying ist jetzt sehr einfach:

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

Anstatt Aufsuchen eines Kategorie-Knoten, um dann eine weitere Abfrage zu tun, nur alles auf einmal:

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

Wenn Sie wollen o aktualisieren Sie eine Kategorie, zu tun, dass in einem Rutsch auch:

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

Schließlich Ihre CategoryAdd Methode derzeit 1) hat ein DB einen vorhandenen Knoten finden schlagen, 2) eine zweite DB prallte gegen einen neuen zu erstellen, 3) ein dritter DB-Treffer, um die ID darauf zu aktualisieren. Stattdessen können Sie all dies zu einem einzigen Aufruf komprimieren zu der Verwendung von 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(); 
} 

Grundsätzlich

  1. nicht Neo4j internes IDs als eine Möglichkeit, Ihre eigene Identität zu hacken um die Verwaltung . (Sie können aber in Zukunft eine Form der automatischen Nummerierung freisetzen. Selbst wenn sie dies tun, werden Domänenidentitäten wie E-Mail-Adressen oder SKUs oder Flughafencodes oder ... bevorzugt. Sie brauchen nicht einmal immer eine ID: Sie können oft auf a schließen Knoten basierend auf seiner Position im Diagramm.)

  2. Im Allgemeinen wird Node<T> mit der Zeit verschwinden. Wenn Sie es jetzt verwenden, sammeln Sie nur Legacy-Code.

  3. Suchen Sie in Beschriftungen und schemabasierte Indexierung. Sie werden Ihnen das Leben erleichtern.

  4. Versuchen Sie, Dinge in der einen Abfrage zu tun. Es wird viel schneller sein.

Hoffe, dass hilft!

+0

Ich nehme an, der Code graphClient.Client sollte graphClient.Cypher sein. Wenn ich eine Abfrage ähnlich der "Abfrage ist einfach ..." versuche, bekomme ich den Fehler {"SyntaxException: Diese Syntax wird nicht mehr unterstützt (fehlende Eigenschaften werden jetzt als Null zurückgegeben). (Zeile 2, Spalte 10) \ n "WHERE (o.Name! = {P0}) \ r \" \ n^"} – Cheval

+0

Verwenden Sie 1.0.0.625 oder höher. Auch habe ich die Tippfehler in der Antwort oben behoben. Dies geschieht, wenn Sie alles aus dem Speicher direkt in eine Textbox eingeben. :) –

+0

Hat das für dich @Cheval funktioniert? Ich habe ein wenig Zeit damit verbracht, diese Antwort zu schreiben, daher wäre es sehr hilfreich, wenn Sie es als akzeptiert markieren würden. –

Verwandte Themen