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>
:
T
represents a MongoDBEntity
class
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.
public ActionResult Index()
{
var _BAuthor = new MongoDbGenericDao.MongoDBGenericDao<Author>(
WebConfigurationManager.ConnectionStrings["MongoServerSettings"].ConnectionString);
return View(_BAuthor.GetAll().Take(10).ToList());
}
[HttpDelete]
public ActionResult Remove(string Id)
{
var _BAuthor = new MongoDbGenericDao.MongoDBGenericDao<Author>(
WebConfigurationManager.ConnectionStrings["MongoServerSettings"].ConnectionString);
var author = _BAuthor.GetByID(Id);
_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);
_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.