Neo4jD–.NET client for Neo4j Graph Database Part 2
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 Part 2 […]
Neo4jD–.NET client for Neo4j Graph DB | Sony Arouje Blog
February 13, 2012 at 8:24 pm