Neo4j with C#, Part 1 — Intro!

Farhad Nowzari
.Net Programming
Published in
4 min readApr 20, 2024

Yes, yes neo4j has a driver for dotnet and why not just simply use that one. There are also several other libraries which are developed as an Object-Graph-Mapping for C#.

Neo4j.Berries.OGM introduction

There is a delicate point here. Dotnet developers are used to using entity framework. So, it is not easy to tell them we have to switch 100% and use a new way of thinking or put cypher strings directly in the code.
These people like it clean :)

Now what is the solution? Neo4j.Berries.OGM

NuGet Gallery | Neo4j.Berries.OGM 1.1.0

We had to develop a library close enough to entity framework and yes it is in our scope to simply extend entity framework core to support neo4j perhaps some day when neo4j starts noticing C# world 😉, but for now this library does the job.

Now if you are interested enough, here is the github repository for Neo4j.Berries.OGM and if you stick a bit longer, you are going to create some data in neo4j with less configs as you think you need 😏

GitHub — berrybeat/Neo4j.Berries.OGM: This repository adds an OGM functionality for csharp

Simple Sample

We are going to implement the typical example from neo4j, which is Movies, directors and actors example.

Let’s say that we want to create the following graph with C# without doing one line of cypher as string in the code.

A simple graph presentation in neo4j

To create a new node with the OGM library, you do everything the same as you do in ef core. Let’s create our node models (the same as entity models).

Person:

public class Person
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Movie> MoviesAsActor { get; private set; } = [];
public List<Movie> MoviesAsDirector { get; private set; } = [];
}

Movie:

public class Movie 
{
public Guid Id { get; set; }
public string Title { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<Person> Actors { get; set; } = [];
public List<Person> Directors { get; set; } = [];
}

As you see, C# is very primitive here. Our object in C# only knows that it owns some properties, but it doesn’t know how are they really related. This is not a challenge only with neo4j, but also when you have a many to many relation in SQL based databases.

To introduce those relations, fluent configuration will come to play, as in ef core where we had to implement IEntityTypeConfiguration<> , here we implement INodeConfiguration<> .

PersonConfiguration:

public class PersonConfiguration : INodeConfiguration<Person>
{
public void Configure(NodeTypeBuilder<Person> builder)
{
builder.HasRelationWithMultiple(x => x.MoviesAsActor, "ACTS_IN", RelationDirection.Out);
builder.HasRelationWithMultiple(x => x.MoviesAsDirector, "DIRECTS", RelationDirection.Out);
}
}

The code above, is defining the label on the director/actor relation including their direction. The RelationDirection.Out means (p:Person)-[:ACTS_IN]->(m:Movie) and the same for the director.

The properties for the relation is still a feature, we are working on and will be introduced soon in v1.2.0.

MovieConfiguration:

public class MovieConfiguration : INodeConfiguration<Movie>
{
public void Configure(NodeTypeBuilder<Movie> builder)
{
builder.HasRelationWithMultiple(x => x.Actors, "ACTS_IN", RelationDirection.IN);
builder.HasRelationWithMultiple(x => x.Directors, "DIRECTS", RelationDirection.IN);
}
}

Well, defining the ACTS_IN and DIRECTS labels are not really necessary here unless you want to create these relations also when creating a movie node.

Btw, did you notice while defining the same relations in movie, the relation direction is different?

From DbContext to GraphContext

Well it is time to see the real magic here. In entity framework, you need to extend DbContext with your own DbContext extension which includes the DbSet<> . In Neo4j.Berries.OGM you will need to extend the GraphContext like below.

public class ApplicationGraphContext(Neo4jOptions options) : GraphContext(options)
{
public NodeSet<Person> People { get; private set; }
public NodeSet<Movie> Movies {get; private set; }
}

Pretty similar right? Not that much different than ef core. It is going to get more familiar when you want to add a new node :)

Let’s add a Person who has acted in a movie in one transaction :)

var person = new Person {
Id = Guid.NewGuid(),
FirstName = "Keanu",
LastName = "Reeves",
MoviesAsActors = new List<Movie> {
new Movie {
Title = "The Matrix"
}
}
};
applicationGraphContext.People.Add(person);
applicationGraphContext.SaveChanges();

Very familiar :)

What happens, is the library will see you are creating a person, so it looks into the person’s fluent configuration. Then it sees you are adding a relation as an actor to the movie The Matrix . It will then try to merge the movie by the properties you have passed and connect the person to the movie in one database transaction.

Conclusion

Neo4j is pretty cool. They have so many fancy examples about knowledge databases and so on, but one important point is, we have to get the data in the safest and yet the most convenient way into the database.
C# is a popular language. It’s structure is very clean which makes it the core language for most companies and developers.
Neo4j is a database when you start thinking about it’s modeling you cannot not think about it anymore.
Now introducing these two giants to each other, I think can be very helpful and useful for most developers and companies.

This library is still under active development and more updates is yet to come and we welcome any contribution to this library from the csharp and neo4j communities.

btw, you can find the video about the preview version here, which basically was an introduction, but now the latest version is v1.1.0 and it is no longer in preview.

I’m planning to post updates for the neo4j features we support in dotnet with this library here, so stay tuned.

Have fun coding ❤️
Farhad

--

--

Farhad Nowzari
.Net Programming

Co-Founder and Software Architect at berrybeat GmbH.