Over a million developers have joined DZone.

Get Reacquainted with the Neo4jClient

DZone's Guide to

Get Reacquainted with the Neo4jClient

· Database Zone
Free Resource

Whether you work in SQL Server Management Studio or Visual Studio, Redgate tools integrate with your existing infrastructure, enabling you to align DevOps for your applications with DevOps for your SQL Server databases. Discover true Database DevOps, brought to you in partnership with Redgate.

Neo4jClient is a .NET client for the Neo4j Rest Server built by a colleague of mine Tatham Oddie. Currently we have a Neo4jClient, which is the latest source code build. This can be found on NuGet with package name Neo4jClient- Neo4jClient is a .NET client for the Neo4j Rest Server.

Source Code at:

It leverages RestSharp and Newtonsoft.json for Rest and Json serialization/deserialization respectively.

The client also supports executing Gremlin queries in the following ways

  • Send raw gremlin statements that return scalar results
  • Send raw gremlin statements that return enumerable collection of nodes
  • Type safe lambda expressions

The raw version is provided to provide flexibility if you find certain lambda expressions are not supported, over time, more expressions will be added. We will be extending the client over time to certain more expressions as we find ourselves needing new expressions.

Lets have a look at some samples.

First you will need to install the package, so at the package console manager type:

install-package neo4jclient

Once this is installed, you can then of course load the IGraphClient in the entry point of your application, manually or using an IoC. The concept of the GraphClient is to provide basic CRUD operations.

The other powerful aspect is that the IGremlinQuery interface provide cool extensions into Gremlin so that a series of extensions methods will support out and in vertices and edges querying.

Below is a diagram illustrating the core concept.Basically we have a GraphClient, GremlinQuery and NodeReference. Notice that you can also query directly off a NodeReference. A NodeReference will represent a reference to a Vertice in the database. A Node will store the actual data, which is cast to a specific type with generics.


Entry Point

Here is sample code in loading the GraphClient using an IoC. It is this easy to get it started.

builder.Register<IGraphClient>(context =>
                var resolver = context.Resolve<IRoleEndpointResolver>();
                var baseUri = resolver.GetNeo4JBaseUri();
                var graphClient = new GraphClient(baseUri);
                return graphClient;

Type Safe Lambda Expressions

Lets look at the cool features we can do. Below is a sample query we can run.

public Node<User> GetUser(User identifier)
            if (identifier.IsSysAdmin)
                return graphClient
                    .In<User>(Administers.TypeKey, u=> u.Username == identifier.Username)

            return graphClient
                .Out<CustomerSite>(Hosts.TypeKey, a => a.Key == identifier.CustomerSiteKey)
                .In<User>(UserBelongsTo.TypeKey, u => u.Username == identifier.Username)

You can even then run queries off a NodeReference, lets look at an example.

public int CreateUser(User user, NodeReference<Company> companyReference)
    return companyReference
                .OutE<User>(u=>u.Username == user.Username)

You have the flexibility.

Creating Nodes and Relationships

You notice that in the above, we had a TypeKey representing the relationship, this is important, you can enforce very strict rules on your nodes, we can define a class that represents a relationship and enforce which source and target nodes or data models it is allowed to have e.g.

public class UserBelongsTo :
        public UserBelongsTo(NodeReference targetNode)
            : base(targetNode)

        public const string TypeKey = "USER_BELONGS_TO";
        public override string RelationshipTypeKey
            get { return TypeKey; }

This means, that you get compile time safety, if you try and create a node in the database with a relationship. Lets look at a Create statement.

public NodeReference CreateUser(User user, NodeReference<CustomerSite> customerSite)
            user.Username = user.Username.ToLowerInvariant();

            var node = graphClient.Create(
                new UserBelongsTo(customerSite));

            return node;

Above, if you tried to swap the create, it would not work e.g.

public NodeReference CreateUser(User user, NodeReference<CustomerSite> customerSite)
            user.Username = user.Username.ToLowerInvariant();
            var node = graphClient.Create(
                new UserBelongsTo(user));

            return node;


You can also update nodes, this is done by passing in a NodeReference and a delegate e.g.

public void UpdateUser(User user, Action<User> updateCallback)
            graphClient.Update(userNode.Reference, u =>

Notice, you also get type safety here as well. The reference to the delegate/method with then get executed when neo4jClient persists the data.

Here is the sample updateCallback call to the above method. Notice I am in fact using the MVC updateModel facility to do the mappings for me, any how, you can update the object using your logic of course, there is no restrictions here. Here “this” refers to the MVC Controller class. It is just a nice way to get MVC to compare the user with the user from the DB and then merge the changes, no need to write logic to merge changes if using in the context of MVC, since it has a nice UpdateModel method that we can use. Othewise you would be using AutoMapper or something even nicer like ValueInjecter(http://valueinjecter.codeplex.com/).

userService.UpdateUser(user, u => this.UpdateModel(u,
                tu => tu.GivenName,
                tu => tu.FamilyName,
                tu => tu.Username,
                tu => tu.EmailAddress,
                tu => tu.BusinessPhone,
                tu => tu.MobilePhone

The update above looks a bit tricky at first as we see a method pointer to a method pointer i.e. two action calls, in fact there are 4, one from the graph client, one from the service, one from the extended version of UpdateModel and then the updateModel itself.

The reason why I have a custom extension method for UpdateModel, is so we can Explicitly set which columns to update. Remember UpdateModel takes a callback and a list of properties to explicitly update, you can of course just call the default version if ALL fields need to be updated.

userService.UpdateUser(user, UpdateModel);

Below is the code for the extended UpdateModel.

public static class ControllerExtensions
        public static void UpdateModel<TModel>(this Controller controller, TModel instanceToUpdate, Action<TModel, string[]> updateModelCallback, params Expression<Func<TModel, object>>[] includeProperties)
            var propertyNames = GetPropertyNames(includeProperties);
            updateModelCallback(instanceToUpdate, propertyNames.ToArray());

        public static IEnumerable<string> GetPropertyNames<T>(params Expression<Func<T, object>>[] action)
            return action
                .Select(property =>
                    var body = property.Body;

                    var unaryExpression = body as UnaryExpression;
                    if (unaryExpression != null) body = unaryExpression.Operand;

                    return (MemberExpression) body;
                .Select(expression => expression.Member.Name);

The above extension method will now allow you to call the UpdateModel with type safety on the model fields to explicitly update. As i mentioned, if you need a simpler update to default to all fields then this call will work:


You can also delete data. Notice the pattern here, get a node reference then run an operation.



You can also create relationships between existing nodes.

graphClient.CreateRelationship(customerNodeReference, new Speaks(languageNode.Reference));

Scalar Query Result – Raw

You might find that a complex lambda is not support, in which case you can execute a raw statement directly an still get type safety e.g.

var count = g.v(0).out('IsCustomer').Count()

Rest under the hood

The Client is smart enough to query the rest endpoint on the server and utilize the correct rest points. So the baseUri would be something like http://locahost:7474/db/data

The graphclient will do a Http get request with application/json to the above endpoint and will retrieve the following response.

  "index" : "http://localhost:7474/db/data/index",
  "node" : "http://localhost:7474/db/data/node",
  "reference_node" : "http://localhost:7474/db/data/node/0"

The above endpoints is the fundamental way to run rest queries, of course the graphclient does all the work for you, however it is always nice to know how it works.


So this is my little primer on the project we working with and it is fantastic working with someone like Tatham Oddie who built this brilliant tool for us to use.

We will be extending this tool as we go along and build new functionality as we need it. Not all Lambda expressions are supported yet and it is limited in tis regard but it is easy to extend going forward.

It’s easier than you think to extend DevOps practices to SQL Server with Redgate tools. Discover how to introduce true Database DevOps, brought to you in partnership with Redgate


Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}