Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am writing a repository for MongoDB and are looking for some review at its current state. I am looking for ways to improve it without adding complexity.

Should I be using a Singelton pattern for the repository?

I was thinking about making the repository static, but I am somewhat reluctant to do it as its generally considered a bad thing, however it would be easier to use considering I use the repository from Razor Templates which I will go further into.

I also wanted to look at the ability to make a generic instantiation of the repository where I would do something like Repository<"users">.Query(x => x["name"] == "joachim").FirstOrDefault(); if that is even possible to to achieve at all, I tried a few different approaches to this but I utterly failed to make it work.

The repository is used for BsonDocument's only, this is due to the fact that the datamodel is not defined within the runtime itself but created by Razor Templates, which leads me to explain briefly how I use the repository, the repository is used in a Razor Templating engine that builds, tests and runs templates as I create these from another source (web interface). This means is that the runtime itself is very minimal, but dynamically extended by templates that contain the datamodel and business objects, transfered using JSON objects. Somewhat flow based programming, and somewhat unix pipelines, I like to think of them as "black boxes" which do not care about context as long as provided data fits it's required criterias, evaluated within each "black box" itself.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using MongoDB.Driver.Linq;
using MongoDB.Driver;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using Newtonsoft.Json;

namespace ibox
{
    class Program
    {
        static void Main(string[] args)
        {
            Repository db = new Repository();

            var r = db.Query("users").Where(x => x["name"] == "joachim").FirstOrDefault();

            if (r != null)
            {
                // Lets spit out what we know exist already.
                Console.WriteLine("User found name: {0} realid: {1}", r["name"], r["_id"]);

                // Personal preference i like to work with dynamic objects. (inside Razor Templates that is)
                var d = r.ToDynamic();

                // Lets see if location is set, if not lets define it.
                if (!DynamicHelper.IsSet(d, "location"))
                {
                    d.location = "Norway";

                    Console.WriteLine("location set to {0}", d.location);

                    // Lets save changes to database.
                    db.Save("users", new BsonDocument(d));
                }
                else
                {
                    Console.WriteLine("location already set to {0}", d.location);
                }
            }
            else
            {
                var user = new BsonDocument
                {
                    { "name", "joachim" }
                };

                db.Insert("users", user);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }

    public class Repository
    {
        public Repository(string database = "default")
        {
            _client = new MongoClient();
            _db = _client.GetServer().GetDatabase(database);
        }

        private MongoClient _client;
        private MongoDatabase _db;

        public MongoCollection GetTable(string Table)
        {
            return _db.GetCollection<BsonDocument>(Table);
        }

        public void Insert(string Table, BsonDocument document)
        {
            BsonValue id;
            if (document.TryGetValue("_id", out id))
            {
                throw new Exception("Can't insert document when _id is already defined, this could cause unexpected duplicates.");
            }
            else
            {
                GetTable(Table).Insert(document);
            }
        }

        public void Save(string Table, BsonDocument document)
        {
            BsonValue id;

            if (document.TryGetValue("_id", out id))
            {
                GetTable(Table).Save(document);
            }
            else
            {
                throw new Exception("Can't save an document when _id is not defined.");
            }
        }

        public void Delete(string Table, BsonDocument document)
        {
            BsonValue id;

            if (document.TryGetValue("_id", out id))
            {
                GetTable(Table).Remove(MongoDB.Driver.Builders.Query.EQ("_id", document["_id"]));
            }
            else
            {
                throw new Exception("Can't delete an document when _id is not defined.");
            }
        }

        public IQueryable<BsonDocument> Query(string Table)
        {
            return GetTable(Table).AsQueryable<BsonDocument>();
        }
    }

    public static class DynamicHelper
    {
        public static bool IsSet(dynamic obj, string field)
        {
            var d = obj as IDictionary<string, object>;

            return d.ContainsKey(field);
        }
    }

    public static class MongoExtensions
    {
        /// <summary>
        /// deserializes this bson doc to a .net dynamic object
        /// </summary>
        /// <param name="bson">bson doc to convert to dynamic</param>
        public static dynamic ToDynamic(this BsonDocument bson)
        {
            var json = bson.ToJson(new JsonWriterSettings { OutputMode = JsonOutputMode.Strict });
            dynamic e =  JsonConvert.DeserializeObject<ExpandoObject>(json);
            BsonValue id;
            if (bson.TryGetValue("_id", out id))
            {
                // Lets set _id again so that its possible to save document.
                e._id = new ObjectId(id.ToString());
            }
            return e;
        }
    }
}
share|improve this question

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.