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

Introduction

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;

				viewModels.Add(vm);
			}
			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;
					}
					context.Scenarios.InsertOne(scenarioDb);
				}

				Loadtest converted = new Loadtest(id, ltParams, agentDb.DomainId, custDb.DomainId, engineerId, ltTypeDb.DomainId, projectDb.DomainId, scenarioDb.DomainId);
				loadtests.Add(converted);
			}
			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.

Advertisement

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:

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

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

%d bloggers like this: