Practical Design Patterns in C# – Builder

Intent

The builder pattern abstracts multiple steps required to create a complex object into a coherent interface. Objects that need several input parameters are prime candidates for refactoring behind a builder object.

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

Problem

To understand the benefits of this pattern, we must first analyse some code that does not utilise it.

var message = new MailMessage("john@example.com",
                "jane@example.com",
                "101 Ways to Refactor",
                "Lorem ipsu…");

Quick, can you identify what is each parameter in this statement? Is John the sender or recipient? How do you add more than one recipient? How does one create HTML-formatted email? These questions are not immediately obvious. And adding more configurability into the MailMessage class would make for ever longer constructor calls.

A more readable alternative is clearly required, at least to retain the maintenance programmer’s sanity for the future. And there’s our hook for the builder pattern.

PlantUML Syntax:<br />
!theme vibrant</p>
<p>interface IMessageBuilder<TMessage> {<br />
+AddressedTo(recipient:string):EmailBuilder<br />
+From(sender:string):EmailBuilder<br />
+WithBody(body:string):EmailBuilder<br />
+WithSubject(subject:string):EmailBuilder<br />
+GetResults():TMessage<br />
}</p>
<p>class EmailBuilder<MailMessage><br />
EmailBuilder ..|> IMessageBuilder<br />
EmailBuilder -left-> MailMessage : builds</p>
<p>class JsonBuilder<string><br />
JsonBuilder ..|> IMessageBuilder<br />
JsonBuilder -right-> string : builds</p>
<p>class Client #palegreen</p>
<p>Client –> EmailBuilder : calls<br />
Client –> JsonBuilder : calls<br />

Solution

The fundamental type in this example is the builder itself, EmailBuilder in this case. This class separates the components of the message into discrete methods.

public class EmailBuilder
{
    private MailMessage _message;

    public EmailBuilder()
    {
        _message = new MailMessage();
    }

    public EmailBuilder AddressedTo(string recipient)
    {
        …
    }

    public EmailBuilder From(string sender)
    {
        …
    }

    public EmailBuilder WithBody(string body)
    {
        …
    }

    public EmailBuilder WithSubject(string subject)
    {
        …
    }

    public MailMessage GetResults()
    {
        return _message;
    }
}

The client code consumes this interface by invoking each method one after the other. All methods in the builder class return the instance itself (i.e. this) so that multiple methods can be chained together into a single, fluid statement.

var builder = new EmailBuilder();
var message = builder.From("john@example.com")
    .AddressedTo("jane@example.com")
    .AddressedTo("jim@example.com")
    .WithSubject("101 Ways to Refactor")
    .WithBody("Lorem ipsu…")
    .GetResults();

This simple class already makes the code exponentially readable and maintainable. But there’s more!

What if the program has to create multiple types of messages, such as an email plus a browser notification encoded into a JSON object? The API from the EmailBuilder can be easily extracted into an IMessageBuilder interface, then applied to different types of builders.

public interface IMessageBuilder<T>
{
    IMessageBuilder WithSubject(string subject);

    IMessageBuilder<T> WithBody(string body);

    IMessageBuilder<T> From(string sender);

    IMessageBuilder<T> AddressedTo(string recipient);

    T GetResults();
 }

This is a generic interface as the return type of each builder differs, depending on the type of message it creates. As a result, the EmailBuilder class definition and method signatures change as shown below. Any code that consumes this class is not affected.

public class EmailBuilder : IMessageBuilder<MailMessage>
{
    private MailMessage _message;

    public EmailBuilder()
    {
        _message = new MailMessage();
    }

    public IMessageBuilder<MailMessage> AddressedTo(string recipient)
    {
        …
    }

    public IMessageBuilder<MailMessage> From(string sender)
    {
        …
    }

    public IMessageBuilder<MailMessage> WithBody(string body)
    {
        …
    }

    public IMessageBuilder<MailMessage> WithSubject(string subject)
    {
        …
    }

    public MailMessage GetResults()
    {
        return _message;
    }
}

This done, we can move on to the JSON builder. For this example, we use types defined in the wildly popular Json.NET library from Newtonsoft.

public class JsonBuilder : IMessageBuilder<string>
{
    private StringBuilder _builder;

    private JsonTextWriter _writer;

    public JsonBuilder()
    {
        _builder = new StringBuilder();
        var sw = new StringWriter(_builder);
        _writer = new JsonTextWriter(sw);
        _writer.WriteStartObject();
    }

    public IMessageBuilder<string> AddressedTo(string recipient)
    {
        _writer.WritePropertyName("AddressedTo");
        _writer.WriteValue(recipient);
        return this;
    }

    public IMessageBuilder<string> From(string sender)
    {
        _writer.WritePropertyName("From");
        _writer.WriteValue(sender);
        return this;
    }

    public IMessageBuilder<string> WithBody(string body)
    {
        _writer.WritePropertyName("Body");
        _writer.WriteValue(body);
        return this;
    }

    public IMessageBuilder<string> WithSubject(string subject)
    {
        _writer.WritePropertyName("Subject");
        _writer.WriteValue(subject);
        return this;
    }

    public string Build()
    {
        _writer.WriteEndObject();
        return _builder.ToString();
    }
}

The client code must instantiate the JsonBuilder and invoke the same methods on it as it does on any other builder. Each builder can have its own customisations, such as only storing a single recipient’s name in the JSON object, which gets overwritten by any subsequent call to AddressedTo().

var builder = new JsonBuilder();
var message = builder.From("john@example.com")
    .AddressedTo("jane@example.com")
    .AddressedTo("jim@example.com")
    .WithSubject("101 Ways to Refactor")
    .WithBody("Lorem ipsu…")
    .GetResults();

Practical Design Patterns in C# – Abstract Factory

Intent

The abstract factory design pattern provides an interface to create instances of related objects without directly specifying their concrete classes. This pattern is a superset of the factory method design pattern, as it separates the creation of an object from consumption, while adding the necessary checks to ensure that only related types of objects can be instantiated at a given time.

Problem

In this example, we look at an application that offers options to connect to SQL Server or MySQL database engines to store its data. A rudimentary way of implementing this functionality is to pepper the code with if-else statements throughout the application, which is impractical, brittle and error prone – all traits to avoid in good code.

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

A database operation requires types to make a connection to the database, a command to contain the query and a type to hold a query parameter. All three have to belong to the same family in order to operate correctly. Swapping any type of them for a type from another family is not allowed. E.g. a MySQL connection instance will not be able to operate with a SQL Server command instance. Therefore, if a program has to offer the ability to work with various types of database engines, it has to guarantee that only compatible types are instantiated at a given time.

PlantUML Syntax:<br />
!theme vibrant</p>
<p>interface IDbFactory {<br />
+ CreateDbConnection()<br />
+ CreateDbCommand()<br />
+ CreateDbParameter()<br />
}</p>
<p>interface IDbConnection<br />
interface IDbCommand<br />
interface IDbParameter</p>
<p>IDbFactory -[hidden]left- IDbParameter<br />
IDbConnection -[hidden]right- IDbCommand<br />
IDbCommand -[hidden]right- IDbParameter</p>
<p>class Client #palegreen</p>
<p>Client -up-> IDbFactory : uses</p>
<p>SqlFactory .down.|> IDbFactory</p>
<p>SqlFactory .down.> SqlConnection : creates<br />
SqlFactory .down.> SqlCommand : creates<br />
SqlFactory .down.> SqlParameter : creates</p>
<p>SqlConnection .down.|> IDbConnection<br />
SqlParameter .down.|> IDbParameter<br />
SqlCommand .down.|> IDbCommand</p>
<p>SqlConnection -[hidden]right- SqlCommand<br />
SqlCommand -[hidden]right- SqlParameter</p>
<p>MySqlFactory .up.|> IDbFactory</p>
<p>MySqlFactory .up.> MySqlConnection : creates<br />
MySqlFactory .up.> MySqlCommand : creates<br />
MySqlFactory .up.> MySqlParameter : creates</p>
<p>MySqlConnection .up.|> IDbConnection<br />
MySqlParameter .up.|> IDbParameter<br />
MySqlCommand .up.|> IDbCommand</p>
<p>MySqlConnection -[hidden]right- MySqlCommand<br />
MySqlCommand -[hidden]right- MySqlParameter</p>
<p>

Solution

This pattern consists of at least 2 types – one to define the factory interface, and a concrete factory class that implements this interface. More families of related objects are added to the application by implementing more factories.

The core API is provided by the IDbFactory interface.

public interface IDbFactory
{
    IDbConnection CreateDbConnection();

    IDbCommand CreateDbCommand();

    IDbDataParameter CreateDbDataParameter();
}

IDbFactory defines methods for the database factory.  IDbConnection, IDbCommand and IDbDataParameter are interfaces provided by the framework in the System.Data namespace. All major third-party database vendors provide bindings for their engines which are compatible with these interfaces.

SQL Server Factory

When the application has to operate against SQL Server, it instantiates the SqlFactory class, which implements the IDbFactory interface, and returns the SQL Server-specific concrete types for IDbConnection, IDbCommand and IDbDataParameter.

public class SqlFactory : IDbFactory
{
    public IDbConnection CreateDbConnection()
    {
        return new System.Data.SqlClient.SqlConnection();
    }

    public IDbCommand CreateDbCommand()
    {
        return new System.Data.SqlClient.SqlDbCommand();
    }

    public IDbDataParameter CreateDbDataParmeter()
    {
        return new System.Data.SqlClient.SqlParameter();
    }
}

MySQL Factory

The MySqlFactory class operates in the same way and returns objects from the MySql.Data.MySqlClient namespace.

public class MySqlFactory : IDbFactory
{
    public IDbConnection CreateDbConnection()
    {
        return new MySql.Data.MySqlClient.MySqlConnection();
    }

    public IDbCommand CreateDbCommand()
    {
        return new MySql.Data.MySqlClient.MySqlCommand();
    }

    public IDbDataParameter CreateDbDataParameter()
    {
        return new MySql.Data.MySqlClient.MySqlParameter();
    }
}

Usage

When the application is launched, it determines the database engine it has to operate against (through UI or configuration or some other means), and then instantiates the appropriate IDbFactory implementation. All objects required to operate on the database are subsequently instantiated from this IDbFactory instance.

public class Program
{
    public static void Main(string[] args)
    {
        IDbFactory factory;

        if ("sql" == args[1])
        {
            factory = new SqlFactory();
        }
        else
        {
            factory = new MySqlFactory();
        }

        using (var connection = factory.CreateDbConnection())
        {
            connection.Open();
            var command = factory.CreateDbCommand();
            command.Connection = connection;
            command.CommandText = "SELECT * FROM [Users] WHERE [UserId] = ?";
            var param = factory.CreateDbDataParameter();
            param.DbType = DbType.Int32;
            param.Value = 42;
            command.Parameters.Add(param);

            command.ExecuteReader();
        }
    }
}

Practical Design Patterns in C# – Factory Method

Intent

The factory method is exactly what is says on the label – a method that produces object instances on demand. Ergo, a factory method. The intent of this pattern is to implement a method (in class or instance scope) that separates the creation of object instances from the consumption. It is often used to lazily instantiate objects during dependency injection. The factory method is the foundation to the abstract factory.

Problem

In this example, we look at an application that has to write data to one of two different file formats. The format is selected at runtime through some kind of user input. The application should be able to select the appropriate file encoder, and request it to serialize the data.

Solution

Separate file writer classes are required for each format, but both must share a common interface. The correct class is instantiated, and its Write method is invoked to perform the save operation.

PlantUML Syntax:<br />
!theme vibrant</p>
<p>interface IFileWriterFactory {<br />
+ Create()<br />
}</p>
<p>interface IFileWriter {<br />
+ Write(data:byte[], fileName:string)<br />
}</p>
<p>IFileWriterFactory ..>IFileWriter : creates</p>
<p>JpegWriter .up.|> IFileWriter<br />
PngWriter .up.|> IFileWriter</p>
<p>JpegWriterFactory .down.|> IFileWriterFactory<br />
PngWriterFactory .down.|> IFileWriterFactory</p>
<p>class Client #palegreen</p>
<p>Client -left-> IFileWriterFactory : uses</p>
<p>

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

All writer classes are required to implement the IFileWriter interface.

public interface IFileWriter
{
    void Write(byte[] data, string filename);
}

This interface is implemented by each writer class. The example below shows the JpegWriter and PngWriter classes.

public class JpegWriter : IFileWriter
{
    void Write(byte[] data, string filename) { … }
}
public class PngWriter : IFileWriter
{
    void Write(byte[] data, string filename) { … }
}

Then a factory interface is declared, and a factory class created for each file type.

public interface IFileWriterFactory
{
    public IFileWriter Create();
}
public class JpegWriterFactory : IFileWriterFactory
{
    public Create()
    {
        return new JpegWriter();
    }
}
public class PngWriterFactory : IFileWriterFactory
{
    public Create()
    {
        return new PngWriter();
    }
}

Usage

The application determines the file type that is required, then invokes the Create method on the appropriate writer factory, which in turn returns a concrete implementation of the IFileWriter class.

The application then invokes the Write method on the writer instance, which handles format-specific details such as endianness, file headers, encoding and more.

static class Program
{
    private static _jpegWriterFactory = new JpegWriterFactory();

    private static _pngWriterFactory = new PngWriterFactory();

    static void Main()
    {
        // Image created and serialized into byte[]
        …

        IFileWriter writer;
        if ("jpg" == args[1])
        {
            writer = _jpegWriterFactory.Create();
        }
        else
        {
            writer = _pngWriterFactory.Create();
        }

        writer.Write(data, "lena");
    }
}

The Content Data Context

This post is part of a series on learning how to use Entity Framework. The rest of the posts in the series are linked below.

Basics of Entity Framework

Code First

Database First


Recall from an earlier post how the DbContext class provides the framework to establish and maintain an open connection to the database. This class is typically extended with a custom context for the application, which allows the developer to add DbSet instances for all the types which are part of the application’s Entity Framework model. Each DbSet property is a collection of entity instances, one for each record in the database. The DbSet is an implementation of IDbSet, which in turn extends IQueryable and IEnumerable.

The DbContext primarily fulfils the following roles.

Querying

Provides an interface to convert statements from LINQ-to-Entities (using queries as well as method syntax) to the SQL syntax specific to the underlying database provider.

Object Materialisation

Converts database records from ADO.NET types such as DataSet to application-specific types through mapping rules.

Change Tracking

Tracks the state of newly created, modified or deleted entities for later committing to the database.

Persistence

Triggering INSERT, UPDATE or DELETE queries on changed entities when the SaveChanges method is called.

Caching

Provides a local, lightweight embedded store for recently retrieved entities to avoid repeated querying against the primary database.

Connecting to the Database

The DbContext class automatically creates a database whose name is derived from the fully-qualified name of the context class. However, this behaviour can be overridden by the programmer by passing a custom connection string, database name, or connection string name from the .config file associated with the running application.

The DbContext class has 7 variants of the constructor to provide different ways of establishing a connection to the database server. The default constructor triggers the behaviour described above.

The constructor variant that takes a string parameter can be used to specify any one of the following.

  1. A standard connection string.
  2. A name of a connection string declared in the configuration file (using the syntax “name=connectionString”).
  3. An Entity Framework connection string declared in the configuration file.
  4. A database name (which is sought on the server .\SQLEXPRESS by default).

Alternative constructors can accept DbConnection or ObjectContext instances instead of a string in order to work with already open connections.

Entity Collections

Records in the database tables are referenced through a DbSet instance, which is an implementation of the set abstract data type specifically designed for Entity Framework. A collection can be non-generic by using the System.Data.Entity.DbSet type, or generic through the use of System.Data.Entity.DbSet<TEntity> type.

Collections of root entities are often exposed as DbSet properties of the application’s context class. But specific entity types can also be extracted from the database by using the Set method (or its generic variant) on the context.

The DbSet class exposes methods to perform your standard CRUD operations on the table. The most important methods are Create, Add, Find, Remove and Attach. You will notice that most of these methods are also available on the Set ADT, which the DbSet type is based on.

Create, Add and Attach sound similar in nature, but are quite different. The Create method instantiates an entity without adding it to the DbSet. The Add method is used to add the entity to the database and mark it for saving later. Finally, Attach adds an entity to the collection without marking it for saving. This is useful for adding temporary entities to read-only collections.

The revised ContentContext class for this application looks like this.

namespace Notadesigner.Blog
{
    public class ContentContext : DbContext
    {
        public ContentContext("Notadesigner")
        {
        }

        public virtual DbSet Blogs
        {
            get;
            set;
        }

        public virtual DbSet Posts
        {
            get;
            set;
        }

        public virtual DbSet Categories
        {
            get;
            set;
        }
    }
}

Based on this structure, the code to retrieve a specific Post by its primary key would be as shown below.

var db = new ContentContext();
var post = db.Posts.Find(10);

Inserting a new record is done in two parts. First, the entity instance is created, then it is added to the collection and the changes saved to the database.

var db = new ContentContext();
var post = db.Posts.Create();
post.Title = "Ways to Try and Take Over the World";
post.Slug = GenerateSlug(post.Title);
// Set other properties on the entity
…
db.Posts.Add(post);
db.SaveChanges();

Attach is useful when you wish to update only a few properties in a record which contains many columns.

var db = new ContentContext();
var post = db.Posts
                .AsNoTracking()
                .Where(p => p.PostId = 10)
                .FirstOrDefault();
// Change the title only
post.Title = "More Ways to Try and Take Over the World";
db.Posts.Attach(post);
db.SaveChanges();

The above code generates an update statement that only affects the Title column, as opposed to updating all the columns in the Posts table.

Deleting records is as simple as finding an entity and marking it for deletion through the Remove method.

var db = new ContentContext();
var post = db.Posts.Find(10);
db.Posts.Remove(post);
db.SaveChanges();

Irrespective of the method used, changes are committed only if the SaveChanges method is called on the context instance.

Conventions, Overrides

When an application using the code-first approach is launched for the first time, Entity Framework creates tables for each entity in the newly created database by converting the entity name into its plural form. For example, the Post entity is associated with a table called “Posts”. The columns in the table are also created automatically based on the entity properties. The property PostId is associated with a column of non-nullable integers of the same name, and it is assigned as the primary key. Similarly, the Title property gets associated with the non-nullable varchar column called Title, whose maximum size is 256 characters. Default conventions can be overridden by using attributes as shown in the previous post, or by using the Fluent API in the initialisation strategy.

Some of the most essential default conventions are shown below.

Schema

The dbo schema is used for all database operations by default.

Tables

Table names are derived from the plural form of the entity they represent.

Primary and Foreign Keys

The Id property or <Entity>Id property is the default primary key. A property with the same name is required in the dependent table. The foreign key is named by combining the dependent navigation property name with the principal primary key property name, separated by an underscore (i.e. Post_OwnerId).

Nullability

Columns to store reference type and nullable primitive type properties are nullable, and primitive type properties are stored in non-nullable columns.

Laying the Groundwork

This post is part of a series on learning how to use Entity Framework. The rest of the posts in the series are linked below.

Basics of Entity Framework

Code First

Database First


Many application developers prefer a code-first approach to implementing a business application with Entity Framework. In this workflow, the programmer begins by writing classes that represent entities in the domain model. As we are aware, each instance of these classes represents a single row from the database. The entity classes correspond to a single table. Public properties on the class are mapped to columns in this table.

For example, a Person class maps to the Persons table in the database in the conventional Entity Framework implementation. The properties Name (string), Age (int) and Gender (enum), correspond to columns Name (nvarchar), Age (int) and Gender (int). When a row is retrieved from the database, the values from its columns are loaded into the properties of this instance. Conversely, modified values in the Person instance can be written back to the table by passing its reference back into the appropriate Entity Framework APIs.

Traditionalists would cringe at the thought of writing application code without a rock-solid database model already in place to back it up. And their outlook is borne out of poor outcomes from automatic table-generation tools. Fortunately, Entity Framework (and several other modern ORM tools) address the table performance characteristics and data integrity problems very well.

If performance or correctness are a problem, they are probably a result of poor description of the application domain by the programmer, rather than a shortcoming of the ORM. Being able to generate entity structures from the application layer does not take away the need to understand the performance characteristics of a database engine. And errors in designing or describing the domain model by inexperienced application developer can still affect the product adversely.

The Business Model

The subject of this exercise is a multi-user blog that can be used to host and serve posts authored by one or more registered users. Posts are created and owned by any user with the appropriate level of access to the editor interface. The owner can then invite more authors to collaborate with them. Collaborators can edit the contents of a post, but cannot delete it.

Finally, anonymous users can view the post by visiting a specific URL for each post. The blog home page is a read-only index of all posts, sorted in reverse chronological order.

The Blog

The blog is the primary entity in our application. It has several descriptive properties of the site itself, such as the name, description and URL. A blog is owned by a user who has super-admin rights to the application. This user has to be created and linked to the blog at the time of setup.

using System.ComponentModel.DataAnnotations;

namespace Notadesigner.Blog.Models
{
    public class Blog
    {
        [Key]
        public int BlogId { get; set; }

        [Required]
        [StringLength(128)]
        public string Name { get; set; }

        [Required]
        public string BaseUrl { get; set; }

        [Required]
        [ForeignKey("Owner")]
        public int OwnerId { get; set; }

        public User Owner { get; set; }

        public ICollection<Category> Categories { get; set; }

        public ICollection<Post> Posts { get; set; }

        public ICollection<User> Users { get; set; }
    }
}

This example introduces several classes from the DataAnnotations namespace which Entity Framework uses when creating the database tables.

Key

The default convention of the framework is to make any property suffixed with the word Id into the primary key for the corresponding table. The Key attribute is not required on the BlogId property. But making it explicit helps maintenance later down the line. The index in the database engine is prefixed with IX_, e.g. IX_PostId.

Required

Nullable columns are the default convention in Entity Framework. The Required attribute changes this and marks them as non-nullable. In addition to enforcing data integrity, this attribute is also used to provide client-side validation in the MVC framework.

StringLength

This attribute defines an explicit maximum on the size of string columns, such as nvarchar in MS SQL. Like Required, this attribute is also usable for client-side validation.

ForeignKey

This attribute defines a foreign key between two entities which enforces relational integrity between tables in the database. The UserId column can only contain a value which already exists in the corresponding column in the User table.

This attribute requires the name of the property which contains the referenced entity record. In this case, the parameter is “Owner”, which is of type User. The User class is described further below.

Users & Roles

A User is the unique identification of a person who operates or accesses content from the blog. Is is composed of a minimum of a unique identification number and a unique user name. A person who wishes to identify as a particular User in the application also requires the password for that account. Passwords are stored as salted and hashed strings.

Roles are coarse-level controls over the actions that a single User can perform in the application. A role is composed of several granular permissions, which can either be explicitly granted or denied. Permissions are not provided by individual modules in the application. For example, the Posts module might have the permissions view, create, edit-title, edit-body, edit-attributes, publish, unpublish and delete. The Users module might offer the permissions create, reset-password, recover, edit-attributes and delete. A Role organises these permissions into a cohesive group of related permissions (e.g. Subscriber, Publisher, Content Creator, Intern, Moderator, Administrator, etc.).

In a typical usage scenario, Users must belong to at least one role in order to be able to perform any useful identifying activity in the application. But the application can also be configured to allow anonymous access to the entire application.

Posts

A Post is a single unit of content in the application. It is created and owned by a single user, and can have one or more collaborators who contribute to the content.

using System.ComponentModel.DataAnnotations;

namespace Notadesigner.Blog.Models
{
    public class Post
    {
        [Key]
        public int PostId { get; set; }

        [Required]
        [StringLength(256)]
        public string Title { get; set; }

        [Required]
        [Index(IsUnique = true)]
        [StringLength(128)]
        public string Slug { get; set; }

        [StringLength(102400)]
        public string Body { get; set; }

        [Required]
        public PostStatus Status { get; set; }

        public DateTime CreatedOn { get; set; }

        public DateTime ModifiedOn { get; set; }

        [Required]
        [ForeignKey("Owner")]
        public OwnerId { get; set; }

        public User Owner { get; set; }

        public ICollection<User> Collaborators { get; set; }

        public ICollection<Category> Categories { get; set; }
    }
}

The class is fairly vanilla, and has all the data annotations which were described previously. It also introduces the Index attribute on the Slug property. A slug is a human-friendly identifier for a post. Words and phrases add more context to the human mind than plain integers. So it is easier to remember and parse what the phrase “a-field-guide-to-entity-framework” points to, than it is to remember the post ID.

In order for slugs to work correctly, they have to be unique. Therefore, the model requires a unique constraint on the value contained in the slug. This instruction is converted into a unique, clustered index in the database table.

A single entity can have multiple indexes, only one of which can be clustered. An index can be composed of multiple properties.

Categories

Categories provide the taxonomy framework to organise posts into groups of common topics. It is a fairly common feature in all content management systems.

using System.ComponentModel.DataAnnotations;

namespace Notadesigner.Blog.Models
{
    public class Category
    {
        [Key]
        public int CategoryId { get; set; }

        [Required]
        [StringLength(256)]
        public string Name { get; set; }

        [Required]
        [Index(IsUnique = true)]
        public string Slug { get; set; }

        [Required]
        [ForeignKey("Owner")]
        public OwnerId { get; set; }

        public User Owner { get; set; }

        public ICollection<Post> Posts { get; set; }
    }
}

These classes collectively provide all the data objects needed to store and manipulate records from the database in the application. The next post in the series will cover the process of connecting to a data source and loading records into memory by using the data context.