Sony Arouje

a programmer's log

Posts Tagged ‘Graph Database

Neo4jD–.NET client for Neo4j Graph Database Part 2

with one comment

This post talks about some of the new functionalities added to Neo4jD in recent days.

Persist Static typed object

In the previous post I explained how to create Node and Relationship using Neo4jD. As you might noticed that Node’s properties are dynamic, for e.g to set FirstName we say ‘node.SetProperty(“FirstName”,”Sony”)’. Just like me most of us are not comfortable with Dynamic properties, that’s why we create static typed entities. This post deals with how to persist static typed entities to Neo4j.

Note: I am not against Dynamics, it’s just a personal preference not to build around Dynamics.

Let’s talk with some examples.

public class Person
{
    public Person()
    {
        this.Address = new Address();
    }
    [EntityId]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Address Address { get; set; }
}

public class Address
{
    [EntityId]
    public int AddressId { get; set; }
    public string Address1 { get; set; }
    public string City { get; set; }
}

 

So I have two classes to hold my data. Let’s see how to persist the object using Neo4jD. The core of Neo4jD is based on Node and Relationship with dynamic properties. On top of the core I added a mapper to do the mapping of Static typed entities to Nodes or relationship. I am not going to much insights of mapper, will just go through some e.g., if you need more insight better go through the Neo4jD in github.

How to Save object 

[TestCase]
public Person SaveTest()
{
    Person person = new Person { FirstName = "Sony", LastName= "Arouje"};
    NodeMapper mapper = new NodeMapper();
    person=mapper.Save<Person>(person);
    Console.WriteLine("Generated Id: " + person.Id.ToString());
    Assert.AreNotEqual(0, person.Id);
    return person;
}

Behind the scenes the NodeMapper uses reflection to get the data from the Person object and create Node object. Let’s see how I am doing it.

public T Save<T>(T entity) where T:class
{
    Node node = this.CreateNode<T>(entity);
    node.Create();
    return MapperHelper.SetIdentity<T>(entity, node.Id);
}

private Node CreateNode<T>(T entity) where T:class
{
    Node node = new Node();
    node.AddProperty("clazz", typeof(T).ToString());
    typeof(T).GetProperties().Where(pr => pr.CanRead && MapperHelper.IsAnId(pr) == false)
    .ToList().ForEach(property =>
    {
        if(MapperHelper.IsPrimitive(property.PropertyType))
            node.AddProperty(property.Name, property.GetValue(entity, null).ToString());
    });

    return node;
}

 

CreateNode function does the mapping. It Iterates through the property and call node.AddProperty(property.Name, property.GetValue()), it’s same as node.AddProperty(“FirstName”,”Sony”).

You might have noticed that the Id field in the class is decorated with ‘EntityId’ attribute. It’s a mandatory attribute to Get or Set the node id to Entity’s id field.

Get Instance from Neo4J

[TestCase]
public void GetPersonById()
{
    NodeMapper mapper = new NodeMapper();
    Person person = mapper.Get<Person>(7);
    Console.WriteLine("Generated Id: " + person.Id.ToString());
    Assert.AreNotEqual(0, person.Id);
    Assert.AreEqual(“Sony”, person.FirstName);
}
 

To get the Person I called mapper.Get with unique id of the person and the mapper will return a valid person if it exist in db. NodeMapper uses below function to generate the object.

public T Get<T>(int id) where T:class
{
    Node node = Node.Get(id);
    T entity = (T)Activator.CreateInstance(typeof(T));
    if (node.GetProperty("clazz")!=typeof(T).ToString())
        throw new InvalidCastException(string.Format("Retrieved object with ID '{0}' is 
          an instance of '{1}' and unable to cast it to '{2}'", id.ToString(), 
          node.GetProperty("clazz"), typeof(T).ToString()));
    typeof(T).GetProperties().Where(pr => pr.CanRead && MapperHelper.IsAnId(pr) == false)
    .ToList().ForEach(property =>
    {
        property.SetValue(entity, MapperHelper.CastPropertyValue(property, 
        node.GetProperty(property.Name)), null);
    });

    entity = MapperHelper.SetIdentity<T>(entity, id);
    return entity;
}

Create Relationships

You can see that Person has an instance of Address, in Graph Person is related to Address. Let’s see how we can create that

[TestCase]
public void CanCreateRelationships()
{
    Person person = new Person { FirsName = "Sony", LastName = "Arouje" };
    person.Address.Address1 = "EcoSpace";
    person.Address.City = "Bangalore";
    NodeMapper mapper = new NodeMapper();
    mapper.CreateRelationshipTo<Person, Address>(person,person.Address);
    Console.WriteLine(person.Id.ToString());
    Assert.AreEqual(1, person.Id); 
}

CreateRelationShipTo function will Save both Person and Address if it’s not saved other wise it’s create a relationship. In Neo4j the relationship will be person->address.

Get Person with Relationship

[TestCase]
public void CanGetRelatedNodes()
{
    NodeMapper mapper = new NodeMapper();
    Person person = mapper.Get<Person>(12);
    IList<Address> address = mapper.GetRelatedEntities<Person, Address>(person, typeof(Address));
    Assert.AreEqual(1, address.Count);
    Assert.AreEqual("EcoSpace", address[0].Address1);
}

 

I know the persisting and retrieving relationships are bit messy, I will work on it to make it more clear and silent.

That’s all about persisting Static typed objects to Neo4j.

In the next post I will talk about Creating Index, Traversal using Germlin and REST.

Neo4jD source code

Advertisements

Written by Sony Arouje

February 10, 2012 at 12:15 am

Posted in .NET

Tagged with , ,

Neo4jD–.NET client for Neo4j Graph DB

with 18 comments

Last couple of days I was working on a small light weight .NET client for Neo4j. The client framework is still in progress. This post gives some existing Api’s in Neo4jD to perform basic graph operations. In Neo4j two main entities are Nodes and Relationships. So my initial focus for the client library is to deal with Node and Relationship. The communication between client and Neo4j server is in REST Api’s and the response from the server is in json format.

Let’s go through some of the Neo4j REST Api’s and the equivalent api’s in Neo4jD, you can see more details of Neo4j RestAPi’s here.

The below table will show how to call Neo4j REST Api directly from an application and the right hand will show how to do the same operation using Neo4jD client.

Neo4j Api Equivalent Neo4jD Api
Create Node

POST http://localhost:7474/db/data/node
Accept: application/json
Content-Type: application/json
{"FirstName" : "Sony"}

Response (click here to see full response)

{
  "outgoing_relationships" : "
http://localhost:7474/db/data/node/……..,
  "data" : {
    "foo" : "bar"
  },…..

}

Node sony=new Node();
sony.AddProperty(“FirstName”,”Sony”);
sony.Create();

Get Node by ID
GET http://localhost:7474/db/data/node/3

Response (click here to see full response)

{
  "outgoing_relationships" :
http://localhost:7474/db/……….,
  "data" : {
    "FirstName" : "Sony"
  },
  "traverse" :
http://localhost:7474/db/data. . .{returnType},
..........
}

Node sony=Node.Get(1);
Assert.AreEqual(“Sony”, sony.GetProperty(“FirstName”);

The Neo4jD will create a Rest request to fetch the Node with Id 1 and parse the json response and set the properties and required field.

Create Relationship between two Nodes

POST http://localhost:7474/db/data/node/1/relationships
Accept: application/json
Content-Type: application/json
{"to" :
http://localhost:7474/db/data/node/2, "type" : "wife"}

Response

(click here to see full response)

Node sony=Node.Get(1); //Get an existing node
//Create a new node
Node viji=new Node();
viji.AddProperty(“FirstName”,”Viji”);
viji.Create();

RelationShip relation=sony.CreateRelationshipTo(viji, “wife”);

 

Client lib is still missing some basic features and I am working on it.

The next important part of the library is Graph traversing. Neo4j supports REST api, Cypher and Germlin for Graph traversing. I am currently writing a query creator for Germlin. So the initial version of Neo4jD will only support Germlin.

If any one wants to join the project feels free to send me a personal mail or add a comment. You all can have a look at the code in Git.

Neo4jD Part 2  Neo4jD Part 3  How to Persist Static typed Entities

 

Neo4jD Git Repository

Written by Sony Arouje

February 3, 2012 at 2:28 pm

Posted in .NET

Tagged with , , ,

%d bloggers like this: