Domain Driven Design with Web API extensions part 15: implementing the ITimetableViewModelRepository interface in MongoDb


In the previous post we implemented the ITimetableRepository interface in the MongoDb repository layer. We saw that the code carried out the same type of logic as its EF counterpart. Most of the new things were related to MongoDb query syntax.

In this post we’ll implement the ITimetableViewModelRepository interface. Make sure you have the DDD demo project open.

ITimetableViewModelRepository in MongoDb

We have a folder called Repositories in the WebSuiteDemo.Loadtesting.Repository.MongoDb project. Insert a class called TimetableViewModelRepository in this folder. Here’s the complete implementation. We’ll comment the code a little bit afterwards:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebSuiteDemo.Loadtesting.Domain;
using WebSuiteDemo.Loadtesting.Repository.MongoDb.DatabaseObjects;
using MongoDB.Bson;
using MongoDB.Driver;
using WebSuiteDDD.Infrastructure.Common.ApplicationSettings;

namespace WebSuiteDemo.Loadtesting.Repository.MongoDb.Repositories
	public class TimetableViewModelRepository : MongoDbRepository, ITimetableViewModelRepository
		public TimetableViewModelRepository(IConnectionStringRepository connectionStringRepository)
			: base(connectionStringRepository)

		public IList<LoadtestViewModel> ConvertToViewModels(IEnumerable<Loadtest> domains)
			List<LoadtestViewModel> viewModels = new List<LoadtestViewModel>();
			LoadTestingContext context = LoadTestingContext.Create(base.ConnectionStringRepository);
			foreach (Loadtest lt in domains)
				LoadtestViewModel vm = new LoadtestViewModel();
				vm.Id = lt.Id;
				AgentMongoDb agentDb = context.Agents.Find<AgentMongoDb>(a => a.DomainId == lt.AgentId).SingleOrDefault();
				if (agentDb == null) throw new ArgumentException("There is no load test agent with the given ID.");
				vm.AgentCountry = agentDb.Location.Country;
				vm.AgentCity = agentDb.Location.City;

				CustomerMongoDb custDb = context.Customers.Find<CustomerMongoDb>(c => c.DomainId == lt.CustomerId).SingleOrDefault();
				if (custDb == null) throw new ArgumentException("There is no customer with the given ID.");
				vm.CustomerName = custDb.Name;

				if (lt.EngineerId.HasValue)
					EngineerMongoDb engDb = context.Engineers.Find<EngineerMongoDb>(e => e.DomainId == lt.EngineerId.Value).SingleOrDefault();
					if (engDb == null) throw new ArgumentException("There is no engineer with the given ID.");
					vm.EngineerName = engDb.Name;

				LoadtestTypeMongoDb loadtestTypeDb = context.LoadtestTypes.Find(l => l.DomainId == lt.LoadtestTypeId).SingleOrDefault();
				if (loadtestTypeDb == null) throw new ArgumentException("There is no load test type with the given ID.");
				vm.LoadtestTypeShortDescription = loadtestTypeDb.Description.ShortDescription;

				ProjectMongoDb projectDb = context.Projects.Find(p => p.DomainId == lt.ProjectId).SingleOrDefault();
				if (projectDb == null) throw new ArgumentException("There is no project with the given ID.");
				vm.ProjectName = projectDb.Description.ShortDescription;

				ScenarioMongoDb scenarioDb = context.Scenarios.Find(s => s.DomainId == lt.ScenarioId).SingleOrDefault();
				if (scenarioDb == null) throw new ArgumentException("There is no scenario with the given ID.");
				vm.ScenarioUriOne = scenarioDb.UriOne;
				vm.ScenarioUriTwo = scenarioDb.UriTwo;
				vm.ScenarioUriThree = scenarioDb.UriThree;

				vm.UserCount = lt.Parameters.UserCount;
				vm.StartDateUtc = lt.Parameters.StartDateUtc;
				vm.DurationSec = lt.Parameters.DurationSec;

			return viewModels;

		public IList<Loadtest> ConvertToDomain(IEnumerable<LoadtestViewModel> viewModels)
			List<Loadtest> loadtests = new List<Loadtest>();
			LoadTestingContext context = LoadTestingContext.Create(base.ConnectionStringRepository);
			foreach (LoadtestViewModel vm in viewModels)
				Guid id = vm.Id;
				LoadtestParameters ltParams = new LoadtestParameters(vm.StartDateUtc, vm.UserCount, vm.DurationSec);

				var agentQueryBuilder = Builders<AgentMongoDb>.Filter;
				var agentCityFilter = agentQueryBuilder.Eq<string>(a => a.Location.City.ToLower(), vm.AgentCity.ToLower());
				var agentCountryFilter = agentQueryBuilder.Eq<string>(a => a.Location.Country.ToLower(), vm.AgentCountry.ToLower());
				var agentCompleteFilter = agentQueryBuilder.And(agentCityFilter, agentCountryFilter);
				AgentMongoDb agentDb = context.Agents.Find(agentCompleteFilter).FirstOrDefault();
				if (agentDb == null) throw new ArgumentException("There is no agent with the given properties.");

				var customerQueryBuilder = Builders<CustomerMongoDb>.Filter;
				var customerQuery = customerQueryBuilder.Eq<string>(c => c.Name.ToLower(), vm.CustomerName.ToLower());
				CustomerMongoDb custDb = context.Customers.Find(customerQuery).SingleOrDefault();
				if (custDb == null) throw new ArgumentException("There is no customer with the given properties.");

				Guid? engineerId = null;
				if (!string.IsNullOrEmpty(vm.EngineerName))
					EngineerMongoDb engDb = context.Engineers.Find(e => e.Name.ToLower() == vm.EngineerName.ToLower()).SingleOrDefault();
					if (engDb == null) throw new ArgumentException("There is no engineer with the given properties.");
					engineerId = engDb.DomainId;

				LoadtestTypeMongoDb ltTypeDb = context.LoadtestTypes.Find(t => t.Description.ShortDescription.ToLower() == vm.LoadtestTypeShortDescription.ToLower()).SingleOrDefault();
				if (ltTypeDb == null) throw new ArgumentException("There is no load test type with the given properties.");

				ProjectMongoDb projectDb = context.Projects.Find(p => p.Description.ShortDescription.ToLower() == vm.ProjectName.ToLower()).SingleOrDefault();
				if (projectDb == null) throw new ArgumentException("There is no project with the given properties.");

				var scenarioQueryBuilder = Builders<ScenarioMongoDb>.Filter;
				var scenarioUriOneFilter = scenarioQueryBuilder.Eq<string>(s => s.UriOne.ToLower(), vm.ScenarioUriOne.ToLower());
				var scenarioUriTwoFilter = scenarioQueryBuilder.Eq<string>(s => s.UriTwo.ToLower(), vm.ScenarioUriTwo.ToLower());
				var scenarioUriThreeFilter = scenarioQueryBuilder.Eq<string>(s => s.UriThree.ToLower(), vm.ScenarioUriThree.ToLower());
				var scenarioCompleteFilter = scenarioQueryBuilder.And(scenarioUriOneFilter, scenarioUriTwoFilter, scenarioUriThreeFilter);
				ScenarioMongoDb scenarioDb = context.Scenarios.Find(scenarioCompleteFilter).SingleOrDefault();
				if (scenarioDb == null)
					scenarioDb = new ScenarioMongoDb()
						DbObjectId = ObjectId.GenerateNewId(),
						DomainId = Guid.NewGuid()
					if (!string.IsNullOrEmpty(vm.ScenarioUriOne))
						scenarioDb.UriOne = vm.ScenarioUriOne;
					if (!string.IsNullOrEmpty(vm.ScenarioUriTwo))
						scenarioDb.UriTwo = vm.ScenarioUriTwo;
					if (!string.IsNullOrEmpty(vm.ScenarioUriThree))
						scenarioDb.UriThree = vm.ScenarioUriThree;

				Loadtest converted = new Loadtest(id, ltParams, agentDb.DomainId, custDb.DomainId, engineerId, ltTypeDb.DomainId, projectDb.DomainId, scenarioDb.DomainId);
			return loadtests;

The implementation of both ConvertToViewModels and ConvertToDomain are again almost identical to their EF counterparts. The only difference is the MongoDb specific syntax, just like we saw in the previous post. We have a mixture of LINQ and Filter based queries in ConvertToDomain.

That’s all for now. We’ll finish the series in the next post where we’ll connect the new MongoDb repository with the rest of the project.

View the list of posts on Architecture and Patterns here.


About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


A great site

iReadable { }

.NET Tips & Tricks

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: