Sony Arouje

a programmer's log

Persist Static typed Entities to Neo4j using Neo4jD

with 3 comments

At the core Neo4jD uses Node and Relationship to persist data to Neo4j graph database. If you want to see how the core is working then visit here. You might notice that, the Node and Relationship is not static typed objects. Most of us work with Static typed entities and want to persist the same. To deal with static typed entities I added a layer on top of Neo4jD core called NodeMapper.

Node Mapper
Below are the features of NodeMapper

  • Map the entity to Node object and persist in Neo4j.
  • Handles the relation between entities, if an entity has a sub entity then NodeMapper will create a relationship between them.
  • Persist the object graph using the Model created, will cover later in the page.
  • Inject interceptor for Lazy loading of related entities.
  • And more

How to Persist entities using NodeMapper
To persist the entities, first we need to draw the object graph of the Entity we need to persist. Let’s have a look at an eg.

public class Order
{
    public Order()
    {
        _orderItems = new List<OrderItem>();
    }

    [EntityId]
    public int Id { get; set; }
    public virtual string Name { get; set; }

    IList<OrderItem> _orderItems;
    public virtual IList<OrderItem> OrderItems 
    { 
        get { return _orderItems; }
        private set { _orderItems = value; }
    }
    public void AddOrderItem(OrderItem item)
    {
        this._orderItems.Add(item);
    }
}

public class OrderItem
{
    public OrderItem()
    {
    }
    public OrderItem(int id, Product product)
    {
        this.Id = id;
        this.Product = product;
    }
    [EntityId]
    public int Id { get; set; }

    public virtual Product Product { get; set; }
}

public class Product
{
    public Product()
    {

    }
    public Product(int id, string productName)
    {
        this.Id = id;
        this.ProductName = productName;
    }
    [EntityId]
    public int Id { get; set; }
    public string ProductName { get; set; }
}

You will notice some rules in defining entities.

  • The unique Id field is decorated with EntityId attribute. It’s mandatory to identify the Id field of the entity.
  • Properties that needs Lazy loading should be virtual.
  • Mandatory to have a default parameter less constructor.

Now let’s define the object graph. This configuration helps NodeMapper to persist the entire Graph. It’s very similar to how we do in Entity Framwork Code first approach.

public class OrderConfiguration:EntityConfiguration<Order>
{
    public OrderConfiguration()
    {
        this.RelatedTo<OrderItem>(o => o.OrderItems);
    }
}

public class OrderItemConfiguration:EntityConfiguration<OrderItem>
{
    public OrderItemConfiguration()
    {
        this.RelatedTo<Product>(oi => oi.Product);
    }
}

public class ProductConfiguration:EntityConfiguration<Product>
{
    public ProductConfiguration()
    {
        this.Leaf();
    }
}

As you can see in the ProductConfiguration, there is no related entity so we marked it as Leaf.

Let’s see how to persist an order

[SetUp]
public void Initialize()
{
    GraphEnvironment.SetBaseUri("http://localhost:7474/");

    ModelBuilder.Add(new OrderConfiguration());
    ModelBuilder.Add(new OrderItemConfiguration());
    ModelBuilder.Add(new ProductConfiguration());
}
[TestCase]
public void SaveOrder()
{
    Order order = new Order();
    order.Id = 0;
    order.Name = "Sony";
    order.AddOrderItem(new OrderItem(0, new Product(0, "Rice")));
    order.AddOrderItem(new OrderItem(0, new Product(0, "Sugar")));

    NodeMapper nodeMapper = new NodeMapper();
    nodeMapper.Save<Order>(order);
    Console.WriteLine(order.Id.ToString());
    Assert.AreEqual(1, order.Id);
}

In the Initialize method of NUnit Test we added EntityConfigurations to ModelBuilder. NodeMapper uses the ModelBuilder to understand the Object graph and uses reflection to traverse through the object graph and persist it.

Lazy Loading

Neo4jD uses Lazy loading to load the related entities, it uses Castle DynamicProxy to intercept property calls and inject lazy loading functionality. To perform lazy loading the property should be virtual, you can see the OrderItems in Order entity.

Retrieve saved Entity

[TestCase]
public void GetOrder()
{
    NodeMapper nodeMapper = new NodeMapper();
    Order order = nodeMapper.Get<Order>(14);
    Assert.AreEqual(14, order.Id);
    foreach (OrderItem item in order.OrderItems)
    {
        Console.WriteLine(item.Id.ToString());
        Product prod = item.Product;
        if (prod != null)
            Console.WriteLine(prod.ProductName);
    }
    Assert.AreEqual(2, order.OrderItems.Count);
}

Visit Github for source code

Written by Sony Arouje

February 21, 2012 at 6:46 pm

Posted in .NET

Tagged with , , , ,

3 Responses

Subscribe to comments with RSS.

  1. […] Neo4jD Part 2  Neo4jD Part 3  How to Persist Static typed Entities […]

    • Hi Hooman,
      Thanks for reporting the issue. I will have a look at and let you know once I fixed it.

      Regards,
      Sony

      Sony Arouje

      May 24, 2012 at 8:33 am

  2. hi. sorry my engllish is not very good. this kind of db was always in my dream. and i want to thank u for this very nice api(neo4jd).

    i have one question. here is my model :

    public abstract class Person

    {

    [EntityId]

    public int Id{get;set;}

    }

    public class Employee : Person

    {

    public string Name {get;set;}

    }

    public class Manager : Person

    {

    public string OfficeName{get;set;}

    }

    public class MyClass

    {

    [EntityId]

    public int Id{get;set;}

    public Person SelectedPerson{get;set;}

    }

    i’ve created map class for all.

    here is the map class of MyClass:

    public class MyClassMap : EntityConfiguration

    {

    public MyClassMap()

    {

    RelatedTo(p => p.SelectedPerson);

    }

    }

    my question is when i create instance from MyClassMap and persist in the neo4j every thing is ok. but when i want to get this object from neo4j i get this error

    Retrieved object with ID ‘1’ is an instance of ‘Domain.Entity.Manager’ and unable to cast it to ‘Domain.Entity.Person’

    what should i do?

    thank you.

    Hooman

    Anonymous

    May 24, 2012 at 12:10 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: