Click here to Skip to main content
Click here to Skip to main content

MongoDB GenericDAO with LINQ support

, 9 Nov 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Lazaro Lima
Architect America-NET Ltda.
Brazil Brazil
Lazaro is a brazilian software architect, live in São Paulo, focusing on web development, NoSql and agile practices for startups.

In his personal life he is a part time runner, speaker, amateur astronomer, gamer and an absorbing knowledge ambulant.
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionUse a single method with a lambda expression as parameter Pinmemberdfvdf567575675528-Aug-13 7:08 
QuestionInjection PinmemberFacundo D24-Jun-13 6:10 
QuestionHow to connect MongoDB database using ASP.NET? PinmemberMember 917112829-Apr-13 2:29 
AnswerRe: How to connect MongoDB database using ASP.NET? PinmemberFacundo D24-Jun-13 9:26 
QuestionDont use inheritance PinmemberRafael Nicoletti4-Feb-13 12:18 
AnswerRe: Dont use inheritance PinmemberFacundo D24-Jun-13 9:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 9 Nov 2012
Article Copyright 2012 by Lazaro Lima
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid