Domain Driven Design with Web API revisited Part 9: the overall database context

Introduction

In the previous post we looked at the repository pattern and abstract repositories in general. We discussed the role of repositories and saw how they can be useful in hiding the implementation details of the concrete data store solution. Repositories are great at limiting direct access to the data store from other layers of the application. They force external callers to go through the domain and its logic when performing data access related operations.

In this post we’ll start implementing the repository for our aggregate root, i.e. the Timetable object. There’s a lot of ground to cover so the topic will span two posts. We won’t create the database yet. That is the subject of another post that follows upon completing the concrete repository layer. The following several posts will be quite technical in nature as opposed to what we’ve seen so far.

EntityFramework code first

As mentioned previously we’ll go for MS SQL Server with EF as the object relational mapper as the concrete data store. It is the first choice for many .NET developers so this sample will appeal to most of them I hope.

There are 3 approaches to working with EF in your project:

  • Database-first: you can point EF to a database and it will create a model for you using T4 templates. You can fine-tune the model in a design surface
  • Model-first: you have no database and use a design surface to draw your model. You can instruct the designer to create the database for you with all the tables
  • Code-first: write your model in code as classes and instruct EF to generate the necessary database and tables

In our case we’ll go with the code-first approach. We don’t have a database so the first option doesn’t apply. Code-first is quite flexible at how you map your proper domain objects with tables in the database.

However, here comes a little warning. I’m not an EF expert. The way I proceed to implement the data store may not be optimal. If you have a thorough knowledge of EF then you may find the solution presented here cumbersome and sub-optimal. Feel free to provide your tips on how to improve it in the comments section below. On the other hand this is not a series on EF. We only need a somewhat realistic data store so that we can persist the domain objects.

There’s actually an introductory series on code-first on this blog, though it doesn’t go through any complex cases. We’ll reuse most ideas presented there. You can find the series starting here.

The overall database context

Open the WebSuite demo we’ve been working on.

We’ll simulate the case where the database might be used by other bounded contexts. E.g. an administrative application may need to access other properties of our domain objects that are not relevant to load testing. Hence we’ll first create a generic EF database context. A load test specific context will follow after that. This will prepare the way to include other contexts later on. You can of course opt for a single overall database context in your own solution but breaking up the full EF context into smaller parts has a good purpose in a DDD project. FYI: I got this idea from Julie Lerman’s excellent post available here.

So, let’s build our complete EF context first with its own data model. Add a new C# class library to the solution. Call it WebSuiteDDD.Repository.EF. Remove Class1. We need to install EF through NuGet. Add the following NuGet package to the repository layer:

Install EntityFramework from NuGet

The most recent stable package is EF 6.1.3 at the time of writing this post.

The SQL database will have its own data model reflected by its tables. In code-first we have the advantage of having no database yet. We’re therefore free to create our tables at will. In fact it’s wise to call the tables and columns the same as they are called in the domain layer in order to preserve the ubiquitous language.

Add a new folder called DataModel to the repository layer. We’ll add copies of our entities and value objects from the domain layer. However, we’ll introduce several additions here and there to demonstrate that the full database model may be different from the actual domain model. Add all of the below objects to the DataModel folder:

Customer:

public class Customer
{
	public Guid Id { get; set; }
	public string Name { get; set; }
	public string Address { get; set; }
	public string MainContact { get; set; }
}

Description:

public class Description
{
	public string ShortDescription { get; set; }
	public string LongDescription { get; set; }
}

LoadtestType:

public class LoadtestType
{
	public Guid Id { get; set; }
	public Description Description { get; set; }
}

Location:

public class Location
{
	public string City { get; set; }
	public string Country { get; set; }
        public double Longitude { get; set; }
	public double Latitude { get; set; }
}

Agent:

public class Agent
{
	public Guid Id { get; set; }
	public Location Location { get; set; }
}

Engineer:

public class Engineer
{
	public Guid Id { get; set; }
	public string Name { get; set; }
	public string Title { get; set; }
	public int YearJoinedCompany { get; set; }
}

LoadtestParameters:

public class LoadtestParameters
{
	public DateTime StartDateUtc { get; set; }
	public int UserCount { get; set; }
	public int DurationSec { get; set; }
}

Project:

public class Project
{
	public Guid Id { get; set; }
	public Description Description { get; set; }
	public DateTime DateInsertedUtc { get; set; }
}

Scenario:

public class Scenario
{
	public Guid Id { get; set; }
	public string UriOne { get; set; }
	public string UriTwo { get; set; }
	public string UriThree { get; set; }
}

Loadtest:

public class Loadtest
{
	public Guid Id { get; set; }
	public Guid AgentId { get; set; }
	public Guid CustomerId { get; set; }
	public Guid? EngineerId { get; set; }
	public Guid LoadtestTypeId { get; set; }
	public Guid ProjectId { get; set; }
	public Guid ScenarioId { get; set; }
	public LoadtestParameters Parameters { get; set; }
}

OK, good, we have the database object models ready. As the last step in this post we need to declare the database tables, or data sets. A data set is represented by the DbSet object in the System.Data.Entity namespace. Insert the following class to the Repository layer:

public class WebSuiteContext : DbContext
{
	public WebSuiteContext() : 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; }

}

We derive from DbContext which will probably look familiar to you if you’ve worked with EF before. We named our context connection string “WebSuiteContext”. We’ll see how the database is generated later on. Also notice that we don’t create data sets for every single object in the data model. E.g. it’s futile to create a separate Description table. We’ll see later how such embedded objects are translated into tables by the EF migration tool.

In the next post we’ll create the load test specific database context.

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.

2 Responses to Domain Driven Design with Web API revisited Part 9: the overall database context

  1. Alex Y says:

    Andras, thanks for your post about this topic. Do you github the source code for this revised version?

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: