Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

NoSqlJsonFile - .NET lightweight Document Store

0.00/5 (No votes)
13 Mar 2013 3  
A NoSQL-like document store in JSON format.

Introduction

NoSqlJsonFile as the name implies, it is designed to be NoSQL-like document store in JSON format, similar to mongoDB - a C++ written document store. NoSqlJsonFile is an open source written in C# for .NET developers who want a true lightweight but powerful storage. NoSqlJsonFile is designed to return enumerable/ generic list type, so you can utilise powerful .NET LINQ/Lambda expression to manipulate data. If you are a .NET Developer and you like mongoDB then you will be in love with NoSqlJsonFile.

So Why NoSqlJsonFile?

File system based and Document-oriented

  • Each table in relational database represents a directory or folder in NoSqlJsonFile.
  • Each row in relational database represents a file in NoSqlJsonFile.
  • It supports one to many relationship andrecursive relationship.
  • The file is stored in JSON Format.
  • The benefit of file system based is that it requires no special program or engine on top.

Portable and lightweight

  • It is intended to be a single source code file so that the developer can copy it and modify it for different projects.

No setup required, just include NoSqlJsonFile.cs file in your project then inherit it

  • All you need to do is just to inherit the NoSqlJsonFile class and off you go!

Using the code

Here is a simple CRUD example to create a customer document store.

Create a document store

To create a new document store, firstly, you need to define a class and then simply assign values to the properties as follows. Save() method is inherited from NoSqlJsonFile class, once Save() method is called, the Unique Id is generated and then the document is saved as a file under your project directory by default (can be changed by define FilePath in your app.config).The file will be named like "Customer94554F9D47E0425B97EBC13614F36CD5"under NoSqlJsonFiles directory.

Customer customer = new Customer();
customer.FirstName = "Anna";
customer.LastName = "Lee";
customer.Save();            

For the class definition, first of all you must inherit your class from NoSqlJsonFile class and then attach[DataContract] attribute to your class. All properties must be attached with the[DataMember] attribute else the properties will be ignored. the property name is strictly an Auto Property i.e., XXX{get;set;}.

[DataContract]
class Customer : NoSqlJsonFile<Customer>
{
  [DataMember]
  public string FirstName { get; set; }
  [DataMember]
  public string LastName { get; set; }
}

If you open the file from your project bin\Debug or bin\Release. You can find the file under folder called NoSqlJsonFiles\Customer94554F9D47E0425B97EBC13614F36CD5.The file is saved as in JSON format with The UniqueId as the document name.

{"DateModfied":"\/Date(1363055984263+1100)\/","UniqueId":"Customer94554F9D47E0425B97EBC13614F36CD5","FirstName":"Anna","LastName":"Lee"}

List a document store

Simply call the inherited List() or Enumerable() method.

foreach (Customer c in Customer.List())
{
   Console.WriteLine( c.FirstName + " " + c.LastName);
}
Update a document from document store
var customer = Customer.Get("Customer94554F9D47E0425B97EBC13614F36CD5");
customer.FirstName = "Annie";
customer.Save();
Delete a document from document store
Customer.Delete("Customer94554F9D47E0425B97EBC13614F36CD5");
Or if the class is an instance of NoSqlJsonFile then call
customer.Delete();

Purchase Order Application Example

We will use a simple Purchase Order as our example which is describe as follows:

A Customer has a one to many relationship with a Order because a customer can place many orders, but a given order can be placed by only one customer.

An Order has a one to many relationship with OrderDetail because each OrderDetail item contains an ordered price and quantity.

An OrderDetail has a one to one relationship to Product, each OrderDetail refers to one Product.

A Product contains the description of item and unit price.

[DataContract]
public class Customer : NoSqlJsonFile<Customer>
{
    [DataMember]
    public string FullName { get; set; }

    [DataMember]
    public string Email { get; set; }

    [DataMember]
    public string Address { get; set; }

    [DataMember]
    public bool ActiveMember { get; set; }

    [DataMember]
    public List<Order> Orders { get; set; }
    
    public bool ProcessEmailSuccessful {get; set;}

    public Order CreateNewOrder(string description = "")
    {
        if (Orders == null)
        {
            Orders = new List<Order>();
        }
        var order = new Order();
        order.OrderedDate = DateTime.Now;
        order.Description = description;
        Orders.Add(order);
        return order;
    }
}

[DataContract]
public class Order : NoSqlJsonFile<Order>
{
    [DataMember]
    public DateTime OrderedDate { get; set; }

    [DataMember]
    public string Description { get; set; }

    [DataMember]
    public List<OrderDetail> OrderDetails { get; set; }
    
    private int _discountPriceOnQuantity = 10;

    public Order AddProductDetail(Product product, float price, int quantity)
    {
        if (OrderDetails == null)
        {
            OrderDetails = new List<OrderDetail>();
        }
        var orderDetail = new OrderDetail();
        orderDetail.OrderedProduct = product;
        orderDetail.OrderedPrice = price;
        orderDetail.Quantity = quantity;
        OrderDetails.Add(orderDetail);

         // 5 percents off on a product order if the total quantity is greater than 10
        if (quantity > _discountPriceOnQuantity){
          orderDetail.OrderedPrice = orderDetail.OrderedPrice * 0.95f;
        }
        return this;
    }

}

[DataContract]
public class OrderDetail : NoSqlJsonFile<OrderDetail>
{
    [DataMember]
    public Product OrderedProduct { get; set; }

    [DataMember]
    public float OrderedPrice { get; set; }

    [DataMember]
    public int Quantity { get; set; }
}

[DataContract]
public class Product : NoSqlJsonFile<Product>
{
    [DataMember]
    public string ProductName { get; set; }

    [DataMember]
    public float UnitPrice { get; set; }
}

Methods and Properties

In Customer class, we have created a method called CreateNewOrder(), this method creates a new order and return the instance of order. We also define a field called ProcessEmailSuccessful this is our programming space property, without defining [DataMember] it will not be saved to file. In Order class, we defined a method called AddProductDetail(), this method creates an OrderDetail and adds a product with order price and qauntity to the Order itself. We also define a private field called _discountPriceOnQuantity, this field will not be saved to file as it is not defined as [DataMember].

Let's do it

In the example, we are going to generate one customer and two products. One customer will make an order with two products.

The customer we want to create is Jerry Liang with the following details

Customer: Jerry Liang
FullName Jerry Liang
Email example@example.com
Address 20 Albert Rd Strathfield NSW Australia
ActiveMember true

The code to generate it.

var customer = new Customer();
customer.FullName = "Jerry Liang";
customer.Email = "example@example.com";
customer.Address = "20 Albert Rd Strathfield NSW Australia";
customer.ActiveMember = true;
customer.Save();

We also need two products one is called HTC One and iPad3.

Product: HTC One
ProductName HTC One
UnitPrice 400.50

Product: iPad3
ProductName iPad3
UnitPrice 550.95

The code to generate them.

var product = new Product();
product.ProductName = "HTC One";
product.UnitPrice = 400.50f;
product.Save();

var product = new Product();
product.ProductName = "iPad3";
product.UnitPrice = 550.95f;
product.Save();

Let's see if we have added them successfully in our document store. Firstly, we could list them all see if they are there.

//I am only interested in Active Members
foreach (var customer in Customer.List().Where(c =>c.ActiveMember))
{
    Console.WriteLine(customer.FullName);
}

foreach (var product in Product.List())
{
    Console.WriteLine(product.ProductName);
}

If nothing goes wrong, we can see the name in our console output. And now I would like to Jerry Liang to make a purchase of HTC One and iPad3 products, it can be done by calling the method CreateNewOrder() which is defined in Customer class.

//Firstly to search the customer by using his full name.
var customer = Customer.List().FirstOrDefault(c => c.FullName == "Jerry Liang");

//and then search the HTC One and iPad3 by using thier product names
var htcOne = Product.List().FirstOrDefault(p => p.ProductName == "HTC One");
var ipad = Product.List().FirstOrDefault(p => p.ProductName == "iPad3");

//after that call CreateNewOrder() method from Customer class to get an Order then call AddProductDetail() method from Order class
var orderId = customer.CreateNewOrder().AddProductDetail(htcOne, 500f, 10).AddProductDetail(ipad, 650.95f, 15).UniqueId;

//Finally we just call Save() method from customer instance to save all changes.
customer.Save();

//if you want to know the order, you can use
var order = Order.Get(orderId);
foreach (var orderDetail in order.OrderDetails)
{
    Console.WriteLine(orderDetail.OrderedProduct + " " + orderDetail.OrderedPrice + " " + orderDetail.Quantity);
}

Points of Interest

In this introduction, I have not mentioned any implmenation of NoSqlJsonFile. It is heavily developed by using .NET Reflection and Serialization library. Also if you are interested and would like to make a contribution please fork me at Github https://github.com/jerry27syd/NoSqlJsonFileProject

History

14th March 2013: Adding Purchase Order Example

13th March 2013: Initial Version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here