A BPlusTree ASP.NET MVC Blog Application

The CSharpTest.Net.BPlusTree NoSQL Key-Value store is adaptible to many types of applications. In this article we use it as a database replacement for MongoDb.

Joe Stevens did a very nice ASP.NET MVC implementation of a Blog Tutorial with MongoDb and the 10Gen C# driver. Since I had recently completed an article featuring the BPlusTree NoSQL Key-Value store I thought, I wonder how difficult would it be to switch out MongoDb for the BPlusTree store?

So, taking Joe's excellent solution as a starting point (why reinvent the wheel, right?) I removed all the MongoDb code and began wiring it up to use the BPlusTree library. It wasn't that difficult, since mostly all I had to do was replace MongoDb CSharp driver calls with the equivalent BPlusTree calls; all the method names could stay the same.

Joe used a MongoDbHelper class as a wrapper, and so I created a BPlusTreeHelper class:

using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Web;
using CSharpTest.Net.Collections;
using CSharpTest.Net.Serialization;

namespace Core.Helpers
{
    public static class BPlusTreeHelper<T> where T : class
    {
         public static BPlusTree<Guid, CSharpTest.Net.Serialization.Post>.Options options;
        public static BPlusTree<Guid, CSharpTest.Net.Serialization.Post> Mapper;

         static BPlusTreeHelper()
        {
            options = new BPlusTree<Guid, CSharpTest.Net.Serialization.Post>.Options(PrimitiveSerializer.Guid, new PostSerializer())
            {
                CreateFile = CreatePolicy.IfNeeded,
                FileName = HttpContext.Current.Server.MapPath("Storage.dat")
            };
            Mapper = new BPlusTree<Guid, CSharpTest.Net.Serialization.Post>(options);
              
        }
    }
}

Joe's PostService class gets replaced with my PostService class:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Text;
using CSharpTest.Net.Serialization;
using System.Text.RegularExpressions;
using System.Web;
using Core.Helpers;
using System.Diagnostics;

namespace Core.Services
{
    public class PostService
    {
         public PostService()
        {
         }

         public void Create(Post post)
        {
            post.Comments = new List<Comment>();
            BPlusTreeHelper<Post>.Mapper.AddOrUpdate(post.PostId, post);
        }

        public void Edit(Post post)
        {
            BPlusTreeHelper<Post>.Mapper.AddOrUpdate(post.PostId, post);
        }

        public void Delete(Guid postId)
        {
            BPlusTreeHelper<Post>.Mapper.Remove(postId);
        }

         public IList<Post> GetPosts()
        {
          return  BPlusTreeHelper<Post>.Mapper.Values.ToList();
         }

         public Post GetPost(Guid id)
        {
            var post = BPlusTreeHelper<Post>.Mapper[id];
            post.Comments = post.Comments.OrderByDescending(c => c.Date).ToList();
             return post;
        }

         public Post GetPost(string url)
        {
            var kvp = BPlusTreeHelper<Post>.Mapper.Where(x => x.Value.Url == url).FirstOrDefault();
            var post = kvp.Value;
            post.Comments = post.Comments.OrderByDescending(c => c.Date).ToList();
             return post;
        }
    }
}

And Joe's CommentService class gets a makeover:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CSharpTest.Net.Serialization;
using Core.Helpers;
using System.Web;


namespace Core.Services
{
    public class CommentService
    {
         public CommentService()
        {
        }

         public void AddComment(Guid postId, Comment comment)
        {
            Post post = BPlusTreeHelper<Post>.Mapper[postId];
             post.TotalComments++;
             post.Comments.Add(comment);
            BPlusTreeHelper<Post>.Mapper.Update(postId, post);
        }

        public void RemoveComment(Guid postId, Guid commentId)
        {
            Post post = BPlusTreeHelper<Post>.Mapper[postId];
            Comment comment = post.Comments.Where(p => p.CommentId == commentId).SingleOrDefault();
            post.Comments.Remove(comment);
            post.TotalComments--;
            BPlusTreeHelper<Post>.Mapper.Update(postId, post);
        }

        public IList<Comment> GetComments(Guid postId, int skip, int limit, int totalComments)
        {
            var newComments = GetTotalComments(postId) - totalComments;
            skip += newComments;
            var post = BPlusTreeHelper<Post>.Mapper[postId];
             return post.Comments.OrderByDescending(c => c.Date).ToList();
         }

         public int GetTotalComments(Guid postId)
        {
            var post = BPlusTreeHelper<Post>.Mapper[postId];
             return post.TotalComments;
        }
    }
}

BplusTree also needs a serializer for any types that aren't included in it's built-in PrimitiveTypes Serializers (int, Guid, etc). So I provide a PostSerializer:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

namespace CSharpTest.Net.Serialization
{
   public class PostSerializer : ISerializer<Post>
   {
       public void WriteTo(Post value, System.IO.Stream stream)
       {
           BinaryFormatter bf = new BinaryFormatter();
           bf.Serialize(stream, value);
       }

       public Post ReadFrom(System.IO.Stream stream)
       {
           BinaryFormatter bf = new BinaryFormatter();
           return (Post) bf.Deserialize(stream);
       }
   }
}

Once you get the hang of working with the BPlusTree library, all kinds of possibilities come into play. Besides the fact that it requires no external server (like MongoDb) and can be added to any application by simply including the two library projects, it offers threadsafe multithreaded access and incredible speed.

You can download the BPlusTreeMVCBlog Visual Studio 2010 solution here.

By Peter Bromberg   Popularity  (3665 Views)