NoSQL Zone is brought to you in partnership with:

Working with a Bangalore based software company. I spend most of my time working in Microsoft Technologies. Author of Neo4jD and iTraveller. Neo4jD is a Neo4j graph database client for .NET and iTraveller is an application to upload photos to both flickr and Facebook. Sony is a DZone MVB and is not an employee of DZone and has posted 25 posts at DZone. You can read more from them at their website. View Full User Profile

Use NodeMapper to Persist Static Typed Entities to Neo4j

06.04.2012
| 3506 views |
  • submit to reddit

At the core, Neo4jD uses Node and Relationship to persist data to the 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);
}

 

Published at DZone with permission of Sony Arouje, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Daniel Slazer replied on Tue, 2012/06/12 - 12:05pm

Personally, I'd like to let the OP have one more chance to try to explain himself. If he can come back with a clear question, great. If he just repeats what he's already asked, or wanders off into further nonsensery, I'd have no problem with it being locked, or even just ignored by those who no longer want to participate.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.