Models and entities oh my
I promised code, so it’s time to get coding! I’m going to start with the api server, then implement the UI on top of that.
The backend is going to be built using ASP.NET 5 and WebAPI for the web layer. The database is going to be sqlite and I’ll be using Entity Framework 7 for the database access layer. These choices are mostly because they’re the defaults in ASP.NET, but I don’t have much experience with Entity Framework so it’s a great opportunity to learn.
I’ll be using Visual Studio 2015 community edition, but since the ASP.NET 5 projects don’t require MSBuild this could easily be Visual Studio Code on Mac or Linux. You’ll need the ASP.NET Release Candidate or a later version.
Setting up
First thing, new project time. In Visual Studio create a new C# WebAPI project targeting asp.net 5, or use yoman to create the template.
Now we have a skeleton project with just what’s needed to run WebAPI. You can
run dnx kestrel
to see the default page, but I’m just going to get started
adding code.
First we need to add entity framework, so add these to the dependencies section of your project.json file:
"EntityFramework.SQLite": "7.0.0-rc1-final",
"EntityFramework.Commands": "7.0.0-rc1-final",
"EntityFramework.Sqlite": "7.0.0-rc1-final"
Visual studio will automatically fetch the nuget packages as you save the
file, if you’re not using Visual Studio you might need to run dnu restore
.
While we’re in project.json we’ll add the entity framework CLI commands, so just add
"ef": "EntityFramework.Commands"
to the commands section. This will let us generate migrations and automate some common entity framework commands.
Model Objects
First we’ll add our models. I’ll just cover a couple here since it’s quite repetitive. Since Categories are central to our data model lets set that up first, then I’ll show the budget relation.
Entity Framework 7 uses the attributes from System.ComponentModel.DataAnnotations to configure the models as Plain Old C# Objects (POCOs, like POJOs from Java-land). This means we don’t need any external XML or C# configuration files or any common base classes to set up our models, which coupled with convention-based configuration makes the models quite succinct. This also means we can treat our models as any other C# object
- they can easily be serialised to JSON or other formats without causing a huge property storm.
Creating the models
Let’s start our category with a name and a sequential key for the primary key.
public class Category
{
[Required]
public int CategoryId { get; set; }
[StringLength(100), Required]
public string Name { get; set; }
}
CategoryId follows an Entity Framework convention so we don’t need to specify that it’s the primary key or that it needs a sequence, it’s just assumed. You can disable or override this if needed, so don’t worry about being stuck with this.
Next up budgets!
public class Budget
{
[Required]
public int BudgetId { get; set; }
[Required]
public Category Category { get; set; }
}
Specifying the Category class will automatically generate the column and foreign key. Now this is only half of the relationship, so let’s go back to Category and add the link to the budget. As we can only have one budget per category this is a simple relationship, so add this to the Category class.
public Budget Budget { get; set; }
Unfortunately this is deceptive. One-to-one relationships need a master side to hold the ID, but there isn’t an attribute for this. We’ll configure this in the Context.
Configuring the context
Next up the db context and the service bindings so entity framework loads properly. Entity Framework uses with a DbContext to hold all the mapped objects and track their changes. You can have multiple contexts if you have different database connections or different object lifecycles, but we only have one and it lives in a SQLite database.
public class MHContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Budget> Budgets { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity(typeof(Category)).HasOne(typeof(Budget)).WithOne();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
var appEnv = (IApplicationEnvironment) CallContextServiceLocator.Locator.ServiceProvider.GetService(typeof(IApplicationEnvironment));
optionsBuilder.UseSqlite($"Data Source={appEnv.ApplicationBasePath}/mh.sqlite");
}
}
The Context class is used both when generating the migrations and when starting the application. OnModelCreating is used to override or add to the models determined from the attributes. In this case Entity Framework is being configured so that Category has one Budget, and the Category table should hold the reference.
OnConfiguring is called when Entity Framework is used to access a database. The only magic here is the CallContextServiceLocator, which is provided as part of ASP.NET. Since this class can’t be created via IoC - the context has to work outside of the built-in ASP.NET IoC chain - a service locator is used..
IoC and migrations
Finally it’s time to add the Entity Framework bindings to Startup.cs, which is the ASP.NET 5 equivalent to Global.asax, but in ASP.NET 5 this is the entry point to the application (you can read command line arguments!)
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddEntityFramework()
.AddSqlite()
.AddDbContext<MHContext>();
}
That’s the end of the boilerplate! Just one more command to run - Entity Framework has to create database scripts if it is going to migrate the database automatically. This has to be done from the command line.
dnx ef migrations add
Entity Framework will add a couple of files to your project containing the database creation scripts, then we’re ready to go!
I’ve skipped over some of the models since there’s not much interesting in them, but th whole solution is up on my github page.
This will set the scene for the api layer, which I’ll cover I’m the next post.