About Mendz.Data.MongoDB

Mendz.Data provided classes and types that allow developers to create ADO.Net compatible data contexts and model "repositories". The primary motivation behind the design is for use with Dapper, a micro-ORM library. If you've read enough about MongoDB, you should know that it is not ADO.Net compatible. Granted, what is the Mendz.Data.MongoDB namespace all about then?

As I See Tech covered Mendz.Data in two related series: Preparing for Dapper and Working with Dapper. A couple of articles were also published to describe how transactions are supported, and another one to fix a flaw in the original design of Mendz.Library.ResultInfo.

Mendz.Data is NOT Dapper-specific. In fact, which is good, Mendz.Data is really ADO.Net-specific. As I See Tech's coverage in the context of Dapper was because of the team to whom the library was originally being offered. Using Dapper allowed the team to dive in to product development faster and sooner without sacrificing their dependable and reliable SQL development skills.

The following describes the features of Mendz.Data:
  • Data contexts are implemented as concrete instances for a specific database (connection string).
  • Repositories are bound to their data context.
  • Separate CRUDS interfaces are provided to allow developers to implement only what's needed by the model.
  • Separate asynchronous CRUDS interfaces are provided to allow developers to implement only what's needed by the model.
  • The overall design shields applications from the data contexts. Applications only need to "know" about the domain models and their respective repositories. Only the repositories "know" about the data contexts. And only the data contexts "know" about the data source/store.
These characteristics motivated the creation of Mendz.Data.MongoDB. Given MongoDB's support for .Net, it is actually possible to follow the same Mendz.Data concepts and designs to create MongoDB targeting data contexts and repositories.

IMongoDbDataContext

It all starts with IMongoDbDataContext:

IMongoDbDataContext.cs
using MongoDB.Driver;
using System;

namespace Mendz.Data
{
    public interface IMongoDbDataContext : IDisposable
    {
        IMongoDatabase Context { get; }

        void CreateContext();
    }
}

Compared to Mendz.Data.IDbDataContext, note that there is no transaction feature. Coming from RDMS like SQL Server and Oracle, MongoDB's transaction support is a bit... "different". MongoDB is natively transactional at per document level. Multi-document transaction, however, is not as straightforward (compared to SQL's BEGIN TRANSACTION, COMMIT and ROLLBACK). It's not that complicated to understand, but I'd rather that you read about it from MongoDB's documentation instead. In a nutshell, there is no "standard" way of doing multi-document transactions in MongoDB... yet. When the time comes, I can revisit this interface to add transactions support at the data context level.

MongoDbDataContextBase


MongoDbDataContextBase.cs
using MongoDB.Driver;

namespace Mendz.Data
{
    public abstract class MongoDbDataContextBase : IMongoDbDataContext
    {
        protected abstract IMongoDatabase BuildContext();

        #region IMongoDbDataContext Support
        protected IMongoDatabase _context = null;
        public IMongoDatabase Context {
            get
            {
                CreateContext();
                return _context;
            }
        }

        public virtual void CreateContext()
        {
            if (_context == null)
            {
                _context = BuildContext();
            }
        }
        #endregion

        #region IDisposable Support
        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    if (_context != null)
                    {
                        //_context.Dispose();
                        _context = null;
                    }
                }
                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
    }
}

This code defines a MongoDbDataContextBase, the base class of MongoDB targeting data contexts. It implements IMongoDbDataContext. Derived classes must implement the abstract BuildContext() method.

MongoDbRepositoryBase


MongoDbRepositoryBase.cs
using System;

namespace Mendz.Data
{
    public abstract class MongoDbRepositoryBase<D> : IDisposable
        where D : IMongoDbDataContext, new()
    {
        protected IMongoDbDataContext DbDataContext { get; set; }

        protected bool DbDataContextOwner { get; set; } = false;

        protected MongoDbRepositoryBase()
        {
            CreateDbDataContext();
        }

        protected MongoDbRepositoryBase(IMongoDbDataContext dbDataContext)
        {
            DbDataContext = dbDataContext;
        }

        protected void CreateDbDataContext()
        {
            if (DbDataContext == null)
            {
                DbDataContext = new D();
                DbDataContextOwner = true;
            }
        }

        #region IDisposable Support
        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    if (DbDataContextOwner)
                    {
                        DbDataContext.Dispose();
                        disposed = true;
                    }
                }
                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
    }
}

This code defines MongoDbRepositoryBase, the base class for "repositories" targeting MongoDB. Note that it uses the same designs and patterns used by Mendz.Data.DbRepositoryBase. This is intentional. It is part of Mendz.Data after all.

So... now, how do you use these?

Comments