0
votes

Some pseudo-code of the model I'm working with:

User { int Id, string Username }
Activity { int Id, string Name }
Place { int Id, string Name }

Basically I have a bunch of Users and they belong to certain places (many to many relationship in RDBMS world). What I'd like to do now that I've created all of the nodes already is create the relationship between them. To do that I believe I need to get references to each node and then simply create the relationship between them.

Note: So far no relationships exist. It does look like in some of the examples they have added the User nodes with a relationship that points to the RootNode but I have no idea why. I'm not sure if I need to do that or not.

More pseudo-code:

var userRef = _graphClient...GetUserNodeWhereIdEquals(user.Id);
// or something like _graphClient.OutV<User>("[[id={0}]]", user.Id)
// or even just _graphClient.V<User>(id == user.Id)
var placeRef = _graphClient...GetPlaceNodeWhereIdEquals(place.Id);

_graphClient...CreateRelationshipBetween(userRef, placeRef, "belongs_to");

Unfortunately the documentation starts off pretty great then goes south when you get to relationships.

Update 3/29/12

Here's the code I have so far:

        foreach (var a in _activityTasks.GetAll())
        {
            _graphClient.Create(a, new ActivityBelongsTo(_graphClient.RootNode));
        }
        foreach (var p in _placeTasks.GetAll().Take(1))
        {
            var placeNode = _graphClient.Create(p, new PlaceBelongsTo(_graphClient.RootNode));
            foreach (var activity in p.Activities)
            {
                Activity activity1 = activity;
                var activityNode = _graphClient.RootNode.In<Activity>(ActivityBelongsTo.TypeKey, a => a.Id == activity1.Id).SingleOrDefault();
                _graphClient.CreateRelationship(placeNode, new PlaceHasActivity(activityNode.Reference));
            }
        }

The activity nodes are created fine. The place node is created fine. An error is now being thrown when trying to get the activityNode. It's a rather large stack trace so I'll try to paraphrase here:

Received an exception when executing the request.

The query was: g.v(p0).in(p1).filter{ it[p2] == p3 }.drop(p4).take(p5)._()

The exception was: Value cannot be null. Parameter name: key System.ArgumentNullException: Value cannot be null.Parameter name: key at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) ... The raw response body was: [ { "outgoing_relationships" : "http://localhost:7474/db/data/node/2/relationships/out", "data" : { "Name" : "Aerobics", "Id" : 2 }, "all_typed_relationships" : "http://localhost:7474/db/data/node/2/relationships/all/{-list|&|types}", "traverse" : "http://localhost:7474/db/data/node/2/traverse/{returnType}", "self" : "http://localhost:7474/db/data/node/2", "property" : "http://localhost:7474/db/data/node/2/properties/{key}", "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/2/relationships/out/{-list|&|types}", "properties" : "http://localhost:7474/db/data/node/2/properties", "incoming_relationships" : "http://localhost:7474/db/data/node/2/relationships/in", "extensions" : { }, "create_relationship" : "http://localhost:7474/db/data/node/2/relationships", "paged_traverse" : "http://localhost:7474/db/data/node/2/paged/traverse/{returnType}{?pageSize,leaseTime}", "all_relationships" : "http://localhost:7474/db/data/node/2/relationships/all", "incoming_typed_relationships" : "http://localhost:7474/db/data/node/2/relationships/in/{-list|&|types}" } ]

Something to do when adding a item to a Dictionary when the key is null. Problem is, I don't see any nulls when I debug on my end, activity1 is there, RootNode is there, TypeKey is a const string.

I'm almost wondering if I should just keep the created nodes within a array or Dictionary myself and then just working with the NodeReference. That's what I'm going to try next.

Later that morning

This seems to load everything into the graph database fine:

var activityNodes = _activityTasks.GetAll().ToDictionary(a => a.Id, a => _graphClient.Create(a, new ActivityBelongsTo(_graphClient.RootNode)));

        foreach (var p in _placeTasks.GetAll())
        {
            var placeNode = _graphClient.Create(p, new PlaceBelongsTo(_graphClient.RootNode));
            foreach (var activity in p.Activities)
            {
                _graphClient.CreateRelationship(placeNode, new PlaceHasActivity(activityNodes[activity.Id]));
            }
        }

        foreach (var u in _userTasks.GetAllUserGraph())
        {
            var userNode = _graphClient.Create(u, new UserBelongsTo(_graphClient.RootNode));
            foreach(var activity in u.Activities)
            {
                _graphClient.CreateRelationship(userNode, new UserParticipatesIn(activityNodes[activity.Id]));
            }
        }

Now the problem is similar to what I had before. Now I want to get an activity that has a relationship to the RootNode:

Node<Activity> activity = _graphClient
                            .RootNode
                            .In<Activity>(ActivityBelongsTo.TypeKey, a => a.Id == 1)
                            .SingleOrDefault();

Throwing the key value can't be null exception again. I think I need to investigate the gremlin syntax more. I'm guessing the problem is there.

This afternoon

Started to experiment with Gremlin queries:

g.v(0).inE.filter{it.label=="ACTIVITY_BELONGS_TO"}.outV.filter{it.Id==1}.Name

works fine. I tried to replicate that using neo4jClient syntax:

_graphClient.RootNode.InE(ActivityBelongsTo.TypeKey).OutV(b => b.Id == 1).SingleOrDefault();

Same null exception, it spits out:

g.v(p0).inE.filter{ it[p1].equals(p2) }.outV.filter{ it[p3] == p4 }.drop(p5).take(p6)._()

which looks right to me, except for the end. Ran this though:

g.v(0).inE.filter{it.label=="ACTIVITY_BELONGS_TO"}.outV.filter{it.Id==1}.drop(0).take(1)._()

And that works fine. Something stinks here...maybe I should try the other library although I liked the de/serialization support. Sigh...

Thought maybe a raw query would work. Nope! This method no longer accepts a string and the required GremlinQuery I have no idea how to you. Grooooooooooooooooan.

var users = graphClient.ExecuteGetAllNodesGremlin<IsCustomer>("g.v(0).out('IsCustomer'){it.'Name' == 'BobTheBuilder'}");

Update 3/30/12

Created a new project, everything below works fine. Super confused why it will work here... :( Maybe version differences, I have no idea.

        var client = new GraphClient(new Uri("http://localhost:7474/db/data"));
        client.Connect();

        client.Create(new User { Id = 1, Username = "joe" }, new UserBelongsTo(client.RootNode));
        client.Create(new User { Id = 2, Username = "cloe" }, new UserBelongsTo(client.RootNode));
        client.Create(new Activity { Id = 1, Name = "Bocce Ball" }, new ActivityBelongsTo(client.RootNode));
        client.Create(new Activity { Id = 2, Name = "Programming" }, new ActivityBelongsTo(client.RootNode));

        var user = client.RootNode.In<User>(UserBelongsTo.TypeKey, u=>u.Id == 1).SingleOrDefault();
        var activity = client.RootNode.In<Activity>(ActivityBelongsTo.TypeKey, a=>a.Id == 1).SingleOrDefault();
        client.CreateRelationship(user.Reference, new Plays(activity.Reference));

        user = client.RootNode.In<User>(UserBelongsTo.TypeKey, u => u.Id == 1).SingleOrDefault();
        activity = client.RootNode.In<Activity>(ActivityBelongsTo.TypeKey, a => a.Id == 1).SingleOrDefault();
1

1 Answers

1
votes

I'm just getting started too. I would suggest you check out this blog: http://romikoderbynew.com/2011/07/30/neo4jclient-primer/

Also, check http://frictionfree.org and its source code (in the about section) for more examples.

  • Creating relationships on existing - as I understand, this is possible. However, it appears to be easier to associate nodes as you create them. From the blog:

You can also create relationships between existing nodes. graphClient.CreateRelationship(customerNodeReference, new Speaks(languageNode.Reference));

  • RootNode - I believe you need to start a query from a node, I don't think you can do a

    SELECT * FROM ... WHERE
    

    Therefore, it would make sense that you need to attach nodes to the root node. This is an example from the FrictionFreeApp:

    var node = graphClient.Create(
            user,
            new UserBelongsTo(rootNode));