Domain Driven Design with Web API revisited Part 10: the load test database context

Introduction

In the previous post we started building our EntityFramework repository layer. In particular we worked on the overall WebSuite database context which is meant to be an overall DB context object for all bounded contexts in the WebSuite application. It can be beneficial for each bounded context to have its own matching DB context so that it can concentrate on its DB-related tasks without interfering with other bounded contexts.

In this post we’ll build the load test DB context. This is also where we’ll implement the abstract repository interface we added earlier to the Domain layer.

The load testing context

Open the WebSuite application we’ve been working on so far. We currently have the following project structure in the demo app:

With common repository layer

Add a C# project library to the LoadTesting folder. Call it WebSuiteDemo.Loadtesting.Repository.EF. Remove Class1 and add the following EntityFramework NuGet package to the project:

Install EntityFramework from NuGet

Also, add references to the WebSuiteDemo.Loadtesting.Domain and WebSuiteDDD.SharedKernel projects.

We’ll do something similar to what we did in the previous post. However, instead of creating DB-specific objects we’ll directly use our load testing domain objects to create the DB sets.

Add the following DbContext object to the new repository layer:

public class LoadTestingContext : DbContext
{
	public LoadTestingContext() : base("WebSuiteContext")
	{
	}

	public DbSet<Agent> Agents { get; set; }
	public DbSet<Customer> Customers { get; set; }
	public DbSet<Engineer> Engineers { get; set; }
	public DbSet<Loadtest> Loadtests { get; set; }
	public DbSet<LoadtestType> LoadtestTypes { get; set; }
	public DbSet<Project> Projects { get; set; }
	public DbSet<Scenario> Scenarios { get; set; }
}

You’ll see that this is almost identical to WebSuiteContext.cs from the previous post. The main difference is that the objects of the DB sets, like Agent, Customer etc. refer to the domain objects in the WebSuiteDemo.Loadtesting.Domain layer.

We can implement the abstract time table repository here. Insert a folder called Repositories and add the following class calledTimetableRepository to it:

public class TimetableRepository : ITimetableRepository
{
	public IList<Loadtest> GetLoadtestsForTimePeriod(DateTime searchStartDateUtc, DateTime searchEndDateUtc)
	{
		LoadTestingContext context = new LoadTestingContext();			
		IList<Loadtest> loadtestsInSearchPeriod = (from l in context.Loadtests
													where (l.Parameters.StartDateUtc <= searchStartDateUtc
																&& SqlFunctions.DateAdd("s", l.Parameters.DurationSec, l.Parameters.StartDateUtc) >= searchStartDateUtc)
															||
															(l.Parameters.StartDateUtc <= searchEndDateUtc
																&& SqlFunctions.DateAdd("s", l.Parameters.DurationSec, l.Parameters.StartDateUtc) >= searchEndDateUtc)
															||
															(l.Parameters.StartDateUtc <= searchStartDateUtc
																&& SqlFunctions.DateAdd("s", l.Parameters.DurationSec, l.Parameters.StartDateUtc) >= searchEndDateUtc)
															||
															(l.Parameters.StartDateUtc >= searchStartDateUtc
																&& SqlFunctions.DateAdd("s", l.Parameters.DurationSec, l.Parameters.StartDateUtc) <= searchEndDateUtc)
													select l).ToList();
		return loadtestsInSearchPeriod;
	}


	public void AddOrUpdateLoadtests(AddOrUpdateLoadtestsValidationResult addOrUpdateLoadtestsValidationResult)
	{
		LoadTestingContext context = new LoadTestingContext();
		if (addOrUpdateLoadtestsValidationResult.ValidationComplete)
		{
			if (addOrUpdateLoadtestsValidationResult.ToBeInserted.Any())
			{
				foreach (Loadtest toBeInserted in addOrUpdateLoadtestsValidationResult.ToBeInserted)
				{
					context.Entry<Loadtest>(toBeInserted).State = System.Data.Entity.EntityState.Added;
				}
			}

			if (addOrUpdateLoadtestsValidationResult.ToBeUpdated.Any())
			{
				foreach (Loadtest toBeUpdated in addOrUpdateLoadtestsValidationResult.ToBeUpdated)
				{
					context.Entry<Loadtest>(toBeUpdated).State = System.Data.Entity.EntityState.Modified;
				}
			}
		}
		else
		{
			throw new InvalidOperationException("Validation is not complete. You have to call the AddOrUpdateLoadtests method of the Timetable class first.");
		}
		context.SaveChanges();
	}


	public void DeleteById(Guid guid)
	{
		LoadTestingContext context = new LoadTestingContext();
		Loadtest loadtest = (from l in context.Loadtests where l.Id == guid select l).FirstOrDefault();
		if (loadtest == null) throw new ArgumentException(string.Format("There's no load test by ID {0}", guid));
		context.Entry<Loadtest>(loadtest).State = System.Data.Entity.EntityState.Deleted;
		context.SaveChanges();
	}
}

The implemented GetLoadtestsForTimePeriod will find all overlapping load tests for two dates. As the Add, AddMinutes, AddSeconds etc. methods of the DateTime object is not supported in Linq to SQL we have to revert to the SqlFunctions object which has a specialised DateAdd function that can be embedded into Linq to SQL statements. In order to find the end date of a load test we add the duration to the “second” field of the start date parameter.

The AddOrUpdateLoadtests method first checks if the validation has been performed before calling the repository. If not, then an exception is raised with a hint how to proceed correctly. Otherwise the method loops through the load tests to be inserted or updated and marks each entity as Added or Modified. EntityFramework will proceed accordingly when the SaveChanges method is called at the end.

In the next post we’ll create the database and perform some initial tests.

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: