Search code examples
c#asp.net-mvcmongodbrepository-patternmongodb-.net-driver

mongodb-c# create document with unique fields


I'm new to mongo so i dont have a clue how to do this.

I'm working on a mvc project with repository pattern, and mongo database, using mongodb-C# driver. I cant figure out how to ensure that some fields are unique when created in database, for example when user registers i want the UserName or email to be unique.

According to mongodb docs this is how you create the unique index

db.accounts.ensureIndex( { "tax-id": 1 }, { unique: true } )

How can i do that with repository pattern and mongodb-C# driver?

This is a sample of the generic repository:

    public class GenericRepository<T> : IGenericRepository<T>
    {
        public static MongoCollection Repository
        {
            get { return MongoHelpers.GetCollection<T>(); }
        }
        public virtual T Save(T pobject)
        {
            //should i modify something here?
            Repository.Save(pobject);
            return pobject;
        }
        public virtual T GetByID(BsonValue id)
        {
            return Repository.FindOneByIdAs<T>(id);
        }
        public virtual T GetByCondition(Expression<Func<T, bool>> condition)
        {
            return Repository.AsQueryable<T>().Where(condition).FirstOrDefault();
        }
        ... more code ...
    }

Here is a sample model:

   public class Membership
    {    
        [BsonId]
        public ObjectId UserId { get; set; }

        public string UserName { get; set; }
        //can it be solved by adding data annotations? - if so, how?
        public string Email{ get; set; }

        public MembershipStatus Status { get; set; }
        ...
    }

Here is a sample of a service layer that calls the methods mentioned above:

private readonly IGenericRepository<Membership> _membershipRepository;

public RegisterService(IGenericRepository<Membership> membershipRepository)
{
    _membershipRepository = membershipRepository;
}

public Membership CreateNewUser(RegisterModel registerModel, Role role, bool requireConfirmationToken)
{
    ...
    var membership = AutoMapper.Mapper.Map<RegisterModel, Membership>(registerModel);
    ...mode code...

    _membershipRepository.Save(membership);
    return membership;
}

I can always search the database to see if a value exists, but isnt there something better/cleaner? Thanks


Solution

  • I've figure out how to handle this one. These 2 sources on stackoverflow helped me doing it:

    1. How to create indexes in MongoDB via .NET
    2. Creating MongoDB Unique Key with C#

    This is the method that I've added in the repository:

    public virtual void CreateIndex(string[] fields)
    {
        foreach (string field in fields)
        {
            if (!Repository.IndexExists(field))
            {
                Repository.EnsureIndex(new IndexKeysBuilder().Ascending(field), IndexOptions.SetUnique(true).SetSparse(true));
            }
        }
    }
    

    And then i have another class where i initialize the database indexes, and i call it in global.asax for example:

    public static class DatabaseConfig
    {
        private static IGenericRepository<Membership> _membershipRepository = new GenericRepository<Membership>();
        private static IGenericRepository<Profile> _profileRepository = new GenericRepository<Profile>();
    
        public static void CreateIndex()
        {
            _membershipRepository.CreateIndex(new string[] { "UserName" });
            _profileRepository.CreateIndex(new string[] { "Email" });
            ... more code ...
        }
    }