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

MongoDB GenericDAO with LINQ support

0.00/5 (No votes)
9 Nov 2012 1  
A C# implementation for GenericDAO pattern for MongoDB with LINQ support.

Introduction

This article describes how to implement an generic DAO pattern using the MongoDB C# driver and how to use it in a simple ASP.NET MVC 3 application.

MongoDBEntity 

To represent all documents in MongoDB we can use any class that inherits from an abstract MongoDB Entity. 

using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;

namespace MongoDbGenericDao
{
    public abstract class MongoDBEntity
    {
        [BsonRepresentation(BsonType.ObjectId)]
        public string Id { get; set; }
    }
}

MongoDBEntity is marked as abstract so it can be used only through specific MongoDBEntity DAO implementations.

[BsonRepresentation(BsonType.ObjectId)] defines what property will be used to be an "_id" identifier in a MongoDB document serialization.

Classes

The Author class will be used by GenericDao.

namespace Modal
{
    public class Author : MongoDBEntity
    {
        public string Name { get; set; }
        public string Email { get; set; }
    }
}

The Generic DAO interface

using System;
using System.Collections.Generic;

namespace MongoDbGenericDao.Interfaces
{
    public interface IDao<T, ID> where T : MongoDBEntity
    {
        T Save(T pobject);
        T GetByID(ID id);
        T GetByCondition(System.Linq.Expressions.Expression<Func<T, bool>> condition);
        IEnumerable<T> GetAll();
        IEnumerable<T> GetAll(System.Linq.Expressions.Expression<Func<T, bool>> condition);
        IEnumerable<T> GetAll(System.Linq.Expressions.Expression<Func<T, bool>> condition, int maxresult, bool orderByDescending);
        IEnumerable<T> Paginate(System.Linq.Expressions.Expression<Func<T, bool>> func, int pagesize, int page, bool pOrderByDescending);
        void Delete(T pobject);
        long Count(System.Linq.Expressions.Expression<Func<T, bool>> condition);
    }
}

On IDao<T, ID>:

  1. T represents a MongoDBEntity class
  2. ID represents the MongoDB "_id" identifier type, string by default

The Generic DAO implementation

using System;
using System.Collections.Generic;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDB.Driver.Builders;
using MongoDB.Bson;
using System.Linq;

namespace MongoDbGenericDao
{
    public class MongoDBGenericDao<T> : Interfaces.IDao<T, string> where T : MongoDBEntity
    {
        private MongoDatabase _repository;
        private readonly string collectioname = typeof(T).Name;

        public MongoDBGenericDao(string pConnectionstring)
        {
            var conn = new MongoConnectionStringBuilder(pConnectionstring);
            _repository = MongoServer.Create(conn).GetDatabase(conn.DatabaseName);
        }

        public T GetByID(string _id)
        {
            return _repository.GetCollection<T>(collectioname).FindOne(Query.EQ("_id", new ObjectId(_id)));
        }

        public IEnumerable<T> GetAll()
        {
            return _repository.GetCollection<T>(collectioname).FindAll();
        }

        public T GetByCondition(System.Linq.Expressions.Expression<Func<T, bool>> condition)
        {
            return _repository.GetCollection<T>(collectioname).AsQueryable().Where(condition).FirstOrDefault();
        }

        public IEnumerable<T> GetAll(System.Linq.Expressions.Expression<Func<T, bool>> condition)
        {
            return _repository.GetCollection<T>(collectioname).AsQueryable().Where(condition).ToList();
        }

        public IEnumerable<T> GetAll(System.Linq.Expressions.Expression<Func<T, bool>> condition, 
               int maxresult, bool orderByDescending = false)
        {
            var query = _repository.GetCollection<T>(collectioname).AsQueryable().Where(condition);

            if (orderByDescending)
                query.OrderByDescending(x => x.Id);
            else
                query.OrderBy(x => x.Id);

            return query.Take(maxresult);
        }

        public T Save(T pobject)
        {
            _repository.GetCollection<T>(collectioname).Save(pobject);
            return pobject;
        }

        public void Delete(T pobject)
        {
            _repository.GetCollection<T>(collectioname).Remove(Query.EQ("_id", new ObjectId(pobject.Id)));
        }

        public long Count(System.Linq.Expressions.Expression<Func<T, bool>> condition)
        {
            return _repository.GetCollection<T>(collectioname).AsQueryable().LongCount();
        }

        public IEnumerable<T> Paginate(System.Linq.Expressions.Expression<Func<T, bool>> func, 
               int pagesize, int page, bool pOrderByDescending = false)
        {
            var query = _repository.GetCollection<T>(collectioname).AsQueryable().Where(func);

            if (pOrderByDescending)
                query.OrderByDescending(x => x.Id);
            else
                query.OrderBy(x => x.Id);

            return query.Skip(pagesize * (page - 1)).Take(pagesize);
        }
    }
}

This implementation offers all CRUD methods with LINQ support and a useful Paginate method.

LINQ support is native on C# driver.

Business implementation

To use the code just inherit the class GenericDao<t,> and specify the IDao<t,> interface. 

using MeuCondominio.Business.Interfaces;
using MeuCondominio.Modal.Concrete;
using MongoDbGenericDao;

namespace MeuCondominio.Business.Business
{
    public class BAuthor : MongoDBGenericDao<Author>, IDao<Author,string>
    {
        public BAuthor(string connectionstring)
            : base(connectionstring)
        {

        }
    }
}

Usage

Create a new ASP.NET MVC 3 application and add the MongoDB connectionstring on the web.config file.

<connectionstrings>
    <clear />
    <add name="MongoServerSettings" connectionstring="server=localhost;database=test"> </add>
</connectionstrings>

On the controllers, just create a business variable from GenericDAO and be happy. 

// GET: /Home/
public ActionResult Index()
{
    var _BAuthor = new MongoDbGenericDao.MongoDBGenericDao<Author>(
        WebConfigurationManager.ConnectionStrings["MongoServerSettings"].ConnectionString);

    //get 10 authors
    return View(_BAuthor.GetAll().Take(10).ToList());
}	

[HttpDelete]
public ActionResult Remove(string Id)
{
    var _BAuthor = new MongoDbGenericDao.MongoDBGenericDao<Author>(
      WebConfigurationManager.ConnectionStrings["MongoServerSettings"].ConnectionString);

    //get author by Id
    var author = _BAuthor.GetByID(Id);

    //remove an author
    _BAuthor.Delete(author);

    return RedirectToAction("Index");
}

[HttpPost]
public ActionResult AddAuthor(string name, string email)
{
    Author author = new Author
    {
        Name = name,
        Email = email
    };

    var _BAuthor = new MongoDbGenericDao.MongoDBGenericDao<Postagem>(
      WebConfigurationManager.ConnectionStrings["MongoServerSettings"].ConnectionString);

    //Adds the author object and redirects to "Index" action
    _BAuthor.Save(author);

    return RedirectToAction("Index");
}

Points of Interest

A good practice is to inject the business class using a dependency injection framework like Ninject or StructureMap.

You can use my MongoDbGenericDAO project on github, I'll be very excited to improve the project. 

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