Domain Driven Design with Web API extensions part 12: seeding the MongoDb database

Introduction

In the previous post we constructed the database objects that represent the database version of the load testing domain objects. Recall that there’s no automated code generation and mapping tool for MongoDb .NET – at least not yet. Therefore decoupling database and domain objects with MongoDb as the backing store usually means some extra coding but in turn you’ll have completely independent database and domain objects.

We also inserted an abstraction and a concrete implementation for the connection string repository.

In this post we’ll seed the database with the same initial values as we had for the EF data store.

Important notice

I’ve made a change to the MongoDb representation of the LoadtestParametersMongoDb value object in the previous post after it was published.

Original:

public class LoadtestParametersMongoDb : MongoDbObjectBase
{
	public DateTime StartDateUtc { get; set; }
	public int UserCount { get; set; }
	public int DurationSec { get; set; }
}

Updated:

public class LoadtestParametersMongoDb : MongoDbObjectBase
{
	public DateTime StartDateUtc { get; set; }
	public int UserCount { get; set; }
	public int DurationSec { get; set; }
	public DateTime ExpectedEndDateUtc { get; set; }
}

I added the ExpectedEndDateUtc property which will be equal to StartDateUtc + DurationSec when seeding the database here below. I decided to add this extra property because it makes the date-based queries in the ITimetableRepository.GetLoadtestsForTimePeriod method a lot easier.

Seeding

Currently we have no records related to load testing in MongoDb so as the first exercise we can enter some data. When we set up the EntityFramework infrastructure we could override the Seed method to add some initial records:

protected override void Seed(WebSuiteContext context)
{
			List<Agent> agents = new List<Agent>();
			Agent amazon = new Agent();
			amazon.Id = Guid.NewGuid();
			amazon.Location = new Location()
			{
				City = "Seattle",
				Country = "USA",
				Latitude = 123.345,
				Longitude = 135.543
			};
//rest of code omitted
}

We’ll create something similar for MongoDb. We’ll work in the MongoDbDatabaseTester project so have it open and ready. We’ll first go through a couple of preparation steps:

First open app.config of MongoDbDatabaseTester and add the following connection string right after the opening configuration node:

<connectionStrings>
	<add name="MongoDbWebSuiteContext" connectionString="mongodb://localhost:27017"/>
</connectionStrings>

The connection string should look familiar from one of the earlier posts.

Next add a project reference to the WebSuiteDemo.Loadtesting.Repository.MongoDb, WebSuiteDDD.Infrastructure.Common and WebSuiteDemo.Loadtesting.Domain projects from MongoDbDatabaseTester.

Then start the MongoDb server by opening a command prompt and running the “mongod” command.

Finally make MongoDbDatabaseTester the startup project.

The MongoDb version of the Seed method is in fact not much different from the EF equivalent. Here are the key differences:

  • We’re using the database objects to enter the records
  • We attach an ObjectId to each record

This last point may be overkill for the value objects as they will be embedded into the JSON document. However, we’ll go ahead with the object IDs anyway. They are not important for the domain model anyway.

You can insert the following Seed method to Program.cs of MongoDbDatabaseTester:

private static void Seed()
{
	LoadTestingContext context = LoadTestingContext.Create(new WebConfigConnectionStringRepository());
	List<AgentMongoDb> agents = new List<AgentMongoDb>();
	AgentMongoDb amazon = new AgentMongoDb();
	amazon.DomainId = Guid.NewGuid();
	amazon.DbObjectId = ObjectId.GenerateNewId();
	amazon.Location = new LocationMongoDb()
	{
		City = "Seattle",
		Country = "USA",
		DbObjectId = ObjectId.GenerateNewId()
	};
	AgentMongoDb rackspace = new AgentMongoDb();
	rackspace.DomainId = Guid.NewGuid();
	rackspace.DbObjectId = ObjectId.GenerateNewId();
	rackspace.Location = new LocationMongoDb()
	{
		City = "Frankfurt",
		Country = "Germany",
		DbObjectId = ObjectId.GenerateNewId()
	};
	AgentMongoDb azure = new AgentMongoDb();
	azure.DomainId = Guid.NewGuid();
	azure.DbObjectId = ObjectId.GenerateNewId();
	azure.Location = new LocationMongoDb()
	{
		City = "Tokyo",
		Country = "Japan",
		DbObjectId = ObjectId.GenerateNewId()
	};
	agents.Add(amazon);
	agents.Add(rackspace);
	agents.Add(azure);
	Task addManyAgentsTask = context.Agents.InsertManyAsync(agents);

	List<CustomerMongoDb> customers = new List<CustomerMongoDb>();
	CustomerMongoDb niceCustomer = new CustomerMongoDb();
	niceCustomer.DomainId = Guid.NewGuid();
	niceCustomer.DbObjectId = ObjectId.GenerateNewId();
	niceCustomer.Name = "Nice customer";

	CustomerMongoDb greatCustomer = new CustomerMongoDb();
	greatCustomer.DomainId = Guid.NewGuid();
	greatCustomer.DbObjectId = ObjectId.GenerateNewId();
	greatCustomer.Name = "Great customer";

	CustomerMongoDb okCustomer = new CustomerMongoDb();
	okCustomer.DomainId = Guid.NewGuid();
	okCustomer.DbObjectId = ObjectId.GenerateNewId();
	okCustomer.Name = "OK Customer";

	customers.Add(niceCustomer);
	customers.Add(greatCustomer);
	customers.Add(okCustomer);
	Task addManyCustomersTask = context.Customers.InsertManyAsync(customers);

	List<EngineerMongoDb> engineers = new List<EngineerMongoDb>();
	EngineerMongoDb john = new EngineerMongoDb();
	john.DomainId = Guid.NewGuid();
	john.Name = "John";
	john.DbObjectId = ObjectId.GenerateNewId();

	EngineerMongoDb mary = new EngineerMongoDb();
	mary.DomainId = Guid.NewGuid();
	mary.Name = "Mary";
	mary.DbObjectId = ObjectId.GenerateNewId();

	EngineerMongoDb fred = new EngineerMongoDb();
	fred.DomainId = Guid.NewGuid();
	fred.Name = "Fred";
	fred.DbObjectId = ObjectId.GenerateNewId();

	engineers.Add(john);
	engineers.Add(mary);
	engineers.Add(fred);
	Task addManyEngineersTask = context.Engineers.InsertManyAsync(engineers);

	List<LoadtestTypeMongoDb> testTypes = new List<LoadtestTypeMongoDb>();
	LoadtestTypeMongoDb stressTest = new LoadtestTypeMongoDb();
	stressTest.DomainId = Guid.NewGuid();
	stressTest.DbObjectId = ObjectId.GenerateNewId();
	stressTest.Description = new DescriptionMongoDb()
	{
		DbObjectId = ObjectId.GenerateNewId(),
		ShortDescription = "Stress test",
		LongDescription = "To determine or validate an application’s behavior when it is pushed beyond normal or peak load conditions."
	};

	LoadtestTypeMongoDb capacityTest = new LoadtestTypeMongoDb();
	capacityTest.DomainId = Guid.NewGuid();
	capacityTest.DbObjectId = ObjectId.GenerateNewId();
	capacityTest.Description = new DescriptionMongoDb()
	{
		DbObjectId = ObjectId.GenerateNewId(),
		ShortDescription = "Capacity test",
		LongDescription = "To determine how many users and/or transactions a given system will support and still meet performance goals."
	};

	testTypes.Add(stressTest);
	testTypes.Add(capacityTest);
	Task addManyLoadtestTypesTask = context.LoadtestTypes.InsertManyAsync(testTypes);

	List<ProjectMongoDb> projects = new List<ProjectMongoDb>();
	ProjectMongoDb firstProject = new ProjectMongoDb();
	firstProject.DomainId = Guid.NewGuid();
	firstProject.DbObjectId = ObjectId.GenerateNewId();
	firstProject.Description = new DescriptionMongoDb()
	{
		DbObjectId = ObjectId.GenerateNewId(),
		ShortDescription = "First project",
		LongDescription = "Long description of first project"
	};

	ProjectMongoDb secondProject = new ProjectMongoDb();
	secondProject.DomainId = Guid.NewGuid();
	secondProject.DbObjectId = ObjectId.GenerateNewId();
	secondProject.Description = new DescriptionMongoDb()
	{
		DbObjectId = ObjectId.GenerateNewId(),
		ShortDescription = "Second project",
		LongDescription = "Long description of second project"
	};

	ProjectMongoDb thirdProject = new ProjectMongoDb();
	thirdProject.DomainId = Guid.NewGuid();
	thirdProject.DbObjectId = ObjectId.GenerateNewId();
	thirdProject.Description = new DescriptionMongoDb()
	{
		DbObjectId = ObjectId.GenerateNewId(),
		ShortDescription = "Third project",
		LongDescription = "Long description of third project"
	};
	projects.Add(firstProject);
	projects.Add(secondProject);
	projects.Add(thirdProject);
	Task addManyProjectsTask = context.Projects.InsertManyAsync(projects);

	List<ScenarioMongoDb> scenarios = new List<ScenarioMongoDb>();
	ScenarioMongoDb scenarioOne = new ScenarioMongoDb();
	scenarioOne.DomainId = Guid.NewGuid();
	scenarioOne.DbObjectId = ObjectId.GenerateNewId();
	scenarioOne.UriOne = "www.bbc.co.uk";
	scenarioOne.UriTwo = "www.cnn.com";

	ScenarioMongoDb scenarioTwo = new ScenarioMongoDb();
	scenarioTwo.DomainId = Guid.NewGuid();
	scenarioTwo.DbObjectId = ObjectId.GenerateNewId();
	scenarioTwo.UriOne = "www.amazon.com";
	scenarioTwo.UriTwo = "www.microsoft.com";

	ScenarioMongoDb scenarioThree = new ScenarioMongoDb();
	scenarioThree.DomainId = Guid.NewGuid();
	scenarioThree.DbObjectId = ObjectId.GenerateNewId();
	scenarioThree.UriOne = "www.greatsite.com";
	scenarioThree.UriTwo = "www.nosuchsite.com";
	scenarioThree.UriThree = "www.neverheardofsite.com";

	scenarios.Add(scenarioOne);
	scenarios.Add(scenarioTwo);
	scenarios.Add(scenarioThree);
	Task addManyScenariosTask = context.Scenarios.InsertManyAsync(scenarios);

	List<LoadtestMongoDb> loadtests = new List<LoadtestMongoDb>();
	LoadtestMongoDb ltOne = new LoadtestMongoDb();
	ltOne.DomainId = Guid.NewGuid();
	ltOne.DbObjectId = ObjectId.GenerateNewId();
	ltOne.AgentId = amazon.DomainId;
	ltOne.CustomerId = niceCustomer.DomainId;
	ltOne.EngineerId = john.DomainId;
	ltOne.LoadtestTypeId = stressTest.DomainId;
	DateTime ltOneStart = DateTime.UtcNow;
	ltOne.Parameters = new LoadtestParametersMongoDb() 
	{ 
		DbObjectId = ObjectId.GenerateNewId(), 
		DurationSec = 60, 
		StartDateUtc = ltOneStart, 
		UserCount = 10,
		ExpectedEndDateUtc = ltOneStart.AddSeconds(60)
	};
	ltOne.ProjectId = firstProject.DomainId;
	ltOne.ScenarioId = scenarioOne.DomainId;

	LoadtestMongoDb ltTwo = new LoadtestMongoDb();
	ltTwo.DomainId = Guid.NewGuid();
	ltTwo.DbObjectId = ObjectId.GenerateNewId();
	ltTwo.AgentId = azure.DomainId;
	ltTwo.CustomerId = greatCustomer.DomainId;
	ltTwo.EngineerId = mary.DomainId;
	ltTwo.LoadtestTypeId = capacityTest.DomainId;
	DateTime ltTwoStart = DateTime.UtcNow.AddMinutes(20);
	ltTwo.Parameters = new LoadtestParametersMongoDb() 
	{ 
		DbObjectId = ObjectId.GenerateNewId(), 
		DurationSec = 120, 
		StartDateUtc = ltTwoStart, 
		UserCount = 40,
		ExpectedEndDateUtc = ltTwoStart.AddSeconds(120)
	};
	ltTwo.ProjectId = secondProject.DomainId;
	ltTwo.ScenarioId = scenarioThree.DomainId;

	LoadtestMongoDb ltThree = new LoadtestMongoDb();
	ltThree.DomainId = Guid.NewGuid();
	ltThree.DbObjectId = ObjectId.GenerateNewId();
	ltThree.AgentId = rackspace.DomainId;
	ltThree.CustomerId = okCustomer.DomainId;
	ltThree.EngineerId = fred.DomainId;
	ltThree.LoadtestTypeId = stressTest.DomainId;
	DateTime ltThreeStart = DateTime.UtcNow.AddMinutes(30);
	ltThree.Parameters = new LoadtestParametersMongoDb() 
	{ 
		DbObjectId = ObjectId.GenerateNewId(), 
		DurationSec = 180,
		StartDateUtc = ltThreeStart, 
		UserCount = 50,
		ExpectedEndDateUtc = ltThreeStart.AddSeconds(180)
	};
	ltThree.ProjectId = thirdProject.DomainId;
	ltThree.ScenarioId = scenarioTwo.DomainId;

	loadtests.Add(ltOne);
	loadtests.Add(ltTwo);
	loadtests.Add(ltThree);
	Task addManyLoadtestsTask = context.Loadtests.InsertManyAsync(loadtests);

	Task.WaitAll(addManyAgentsTask, addManyCustomersTask, addManyEngineersTask, addManyLoadtestTypesTask
		, addManyProjectsTask, addManyScenariosTask, addManyLoadtestsTask);
}

Call the Seed method from Main and press F5. If all goes well the method should execute without any errors.

The mongod command window should have a long list of log messages similar to the following:

……

2015-12-10T21:53:11.647+0100 I WRITE [conn6] insert WebSuite.LoadtestTypes qu
ery: { _id: ObjectId(‘5669e63726c8061c1807df6d’), DomainId: BinData(3, 41DCF526C
3BF0941A415831C17E55C5D), Description: { _id: ObjectId(‘5669e63726c8061c1807df6e
‘), ShortDescription: "Stress test", LongDescription: "To determine or validate
an application’s behavior when it is pushed beyond normal or peak load condition
s." } } ninserted:1 keyUpdates:0 writeConflicts:0 numYields:0 locks:{ Global: {
acquireCount: { r: 2, w: 2 } }, MMAPV1Journal: { acquireCount: { w: 8 }, acquire
WaitCount: { w: 2 }, timeAcquiringMicros: { w: 24150 } }, Database: { acquireCou
nt: { w: 1, W: 1 } }, Collection: { acquireCount: { W: 1 } }, Metadata: { acquir
eCount: { W: 4 } } } 286ms
2015-12-10T21:53:11.648+0100 I COMMAND [conn6] command WebSuite.$cmd command: i
nsert { insert: "LoadtestTypes", ordered: true, documents: 2 } keyUpdates:0 writ
eConflicts:0 numYields:0 reslen:40 locks:{ Global: { acquireCount: { r: 3, w: 3
} }, MMAPV1Journal: { acquireCount: { w: 10 }, acquireWaitCount: { w: 2 }, timeA
cquiringMicros: { w: 24150 } }, Database: { acquireCount: { w: 2, W: 1 } }, Coll
ection: { acquireCount: { W: 2 } }, Metadata: { acquireCount: { W: 4 } } } 288ms

….

So our commands have been registered apparently.

Open another command prompt and start a MongoDb client by the “mongo” command.

Execute the following command:

show databases

It should show Loadtests along with one or more databases but we don’t care about those.

Next execute…

use Loadtests

…and then…

show collections

The “show collections” command should list the following collection names:

Agents
Customers
Engineers
LoadtestTypes
Loadtests
Projects
Scenarios
system.indexes

This is a great example of MongoDb’s flexibility. We wanted to enter a couple of records into some collections and a database that didn’t exist beforehand. Who cares? MongoDb created them for us on the fly.

Now let’s check whether our initial records have been saved. The find() method in MongoDb will retrieve all records from a collection. It’s equivalent to “SELECT * FROM” in SQL. We’ll first look into the Agents collection. Run the following JavaScript command in the MongoDb client window:

db.Agents.find()

It should respond with a JSON showing 3 records similar to the following:

{ "_id" : ObjectId("5669ebdd26c80619b43c7793"), "DomainId" : "5c81baf6-ed9b-4b0c
-818b-2ce608b80070", "Location" : { "_id" : ObjectId("5669ebdd26c80619b43c7794")
, "City" : "Seattle", "Country" : "USA" } }
{ "_id" : ObjectId("5669ebdd26c80619b43c7795"), "DomainId" : "1a7cf2b8-c7af-4d2a
-a86e-dad62850522d", "Location" : { "_id" : ObjectId("5669ebdd26c80619b43c7796")
, "City" : "Frankfurt", "Country" : "Germany" } }
{ "_id" : ObjectId("5669ebdd26c80619b43c7797"), "DomainId" : "13f5c999-47c9-4a3c
-ab50-97e9da47758d", "Location" : { "_id" : ObjectId("5669ebdd26c80619b43c7798")
, "City" : "Tokyo", "Country" : "Japan" } }

It’s definitely looking good.

You can look into the the other collections using the find() function and see if all the initial records in the Seed method have been entered.

Great, we are making progress. In the next post we’ll look at a couple of basic database operations through the .NET driver.

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.

One Response to Domain Driven Design with Web API extensions part 12: seeding the MongoDb database

  1. Pingback: Domain Driven Design with Web API extensions part 13: query examples with the MongoDb driver | Dinesh Ram Kali.

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 )

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: