Simple Factory Pattern Example in C#

With the Factory Pattern we provide a clean way to instantiate an object unknown to us at the time of implementation. The only thing we know is the interface of the object with a set of predefined properties and methods we need to use.

In this example we create a Food Factory from a configuration file setting. The factory provides us with the proper kind of food. A call to the Food’s EatIt method shows us a debug message stating the effect this food has on our body. Take a look at the class diagram.

Factory Pattern Food Example ClassDiagram

In our application configuration file we provide the fully qualified type name for the factory we want to use. In this case we go for the FastFood Factory (be honnest).

<applicationSettings>
  <FactoryPatternTests.Properties.Settings>
    <setting name="FoodFactory" serializeAs="String">
      <value>
        FactoryPattern.FoodFactories.FastFoodFactory
      </value>
    </setting>
  </FactoryPatternTests.Properties.Settings>
</applicationSettings>

Let’s write a little test to see the factory pattern in action. In our test we have a method called CreateFoodFactory. This method uses the FoodFactory setting we provided in our app.config. Next we load the FoodFactory assembly by using some magic reflection. Finally we call CreateInstance on this assembly with our factory name. We return the result as an IFoodFactory.

In our main program we can now instantiate some Food Factory, let it create some Food and let us eat it. We do not know or have to know what kind of factory or food we create. We just call on the interfaces.

using System.Linq;
using System.Reflection;
using FactoryPattern.Food;
using FactoryPattern.FoodFactories;
using FactoryPatternTests.Properties;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FactoryPatternTests
{
    [TestClass]
    public class FoodFactoryTests
    {
        [TestMethod]
        public void CreateSomeFood()
        {
            IFoodFactory factory = CreateFoodFactory();
            IFood food = factory.CreateFood();

            food.EatIt();
        }

        private IFoodFactory CreateFoodFactory()
        {
            string factoryName = Settings.Default.FoodFactory.Trim();
            Assembly assembly = Assembly.Load(factoryName.Split('.').First());
            object instance = assembly.CreateInstance(factoryName);

            return (IFoodFactory) instance;
        }
    }
}

Factory Pattern Test Result

Using Entity Framework DbSet Local

A DbSet in an Entity Framework DbContext has a Local property that let us access entities already retrieved within the scope of the DbContext. This way it is possible to further query a local entity set, without sending a query to the database. This can lead to highly efficient queries, if you handle it with a little caution.

In the example below we first send a query to the database for all AssemblyItems with a higher price than 10. Before we issue the query back to the database we ask for the AssemblyItem DbSet Local count. Since we did not retrieve any entities, this should be zero.

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void LocalAndDatabaseCountTest()
        {
            using (var bomContext = new BomContext())
            {
                IQueryable<AssemblyItem> query =
                    bomContext.AssemblyItems
                        .Where(ai => ai.Price > 10m);

                Debug.WriteLine(
                    "Local count is {0}",
                    bomContext.AssemblyItems.Local.Count);

We issue a ToList and we make a roundtrip to the database, retrieving all AssemblyItems we asked for. Again we peek at our Local count. This time we have a total of four AssemblyItems stored in our local cache.


                List<AssemblyItem> assemblyItems = query.ToList();

                Debug.WriteLine(
                    "Local count is {0}",
                    bomContext.AssemblyItems.Local.Count);

                

Lets query the local cache of AssemblyItems and ask for those with a quantity higher than six. Again we take a look at the Local count and see there are two entities that meet our requirements. Note that if we use Local we query against an ObservableCollection type and that the return type is an IEnumerable, not an IQueryable.


                IEnumerable<AssemblyItem> localQuery =
                    bomContext.AssemblyItems.Local
                        .Where(ai => ai.Quantity > 6);

                Debug.WriteLine(
                    "Local query count is {0}",
                    localQuery.Count());

Finally we head back to the database to issue the same query. If we ask for our Local count now, we see there is a row added from the database, making it a total of three. This may be a discrepancy we need to be aware of depending on what we want to achieve while querying the DbSet locally cached entities. With Local we most often query a subset of the rows in the database. If that’s what we want, Local can be our highly-performing friend.


                IQueryable<AssemblyItem> dbQuery =
                    bomContext.AssemblyItems
                        .Where(ai => ai.Quantity > 6);

                Debug.WriteLine(
                    "Database query count is {0}",
                    dbQuery.Count());
            }
        }
    }
}

Entity Framework Local and Database Count Test

Entity Framework Add Remove Attach and Detach

The DbContext of Entity Framework lets us add, remove, attach and detach entities to and from it. Calling SaveChanges on the DbContext the Entity Framework performs different actions on entities dependant on their EntityState. So an added entity gets inserted, a removed entity gets deleted and so on.

In this example we use the AssemblyItem entity from a previous post to perform some of the most common actions on the entities and DbContext. All the tests below passed.

Add an Entity
To add an entity to the DbContext we instantiate an object of the entity type and call the DbSet Add method. The added entity gets an ‘added’ state. Once we call SaveChanges the entity is saved to the database. The entity now has an ‘unchanged’ state. We call the Entry method on the DbContext to find the state for a given entity.

using System.Data;
using System.Data.Entity;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void AddingEntitySetStateToAdded()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();
            AssemblyItem assemblyItem = CreateAssemblyItemStub();

            bomContext.AssemblyItems.Add(assemblyItem);

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Added);
        }

        [TestMethod]
        public void CallingSaveChanesOnAddedEntitySetStateToUnchanged()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();
            AssemblyItem assemblyItem = CreateAssemblyItemStub();

            bomContext.AssemblyItems.Add(assemblyItem);
            bomContext.SaveChanges();

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Unchanged);
        }

        private AssemblyItem CreateAssemblyItemStub()
        {
            const int bomId = 1;

            var assemblyItem =
                new AssemblyItem
                    {
                        BillOfMaterialsId = bomId,
                        Description = "Painter's putty",
                        PartNumber = "Glib043",
                        Price = 15.48m,
                        Quantity = 40,
                    };

            return assemblyItem;
        }
    }
}

Remove an Entity
If we have an entity we do not longer wish to store in the database we can call Remove on the DbContect for this entity. After this operation the state changes to ‘deleted’. To really delete the entity from the database we need to finally call SaveChanges. After that the entity state is ‘detached’ from the DbContext.

using System.Data;
using System.Data.Entity;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void RemoveEntitySetStateToDeleted()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();
            AssemblyItem assemblyItem = bomContext.AssemblyItems.First();

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Unchanged);

            bomContext.AssemblyItems.Remove(assemblyItem);

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Deleted);

            bomContext.SaveChanges();

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Detached);
        }
    }
}

Attach an Entity
If we have an entity which already exists in the database but is somehow unattached from the DbContext we can call Attach on the DbSet to let Entity Framework get back to work with tracking changes. The state after attaching an entity is by default ‘unchanged’.

using System.Data;
using System.Data.Entity;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void AttachEntitySetStateToUnchanged()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();
            AssemblyItem assemblyItem = GetDetachedExistingAssemblyItem();

            bomContext.AssemblyItems.Attach(assemblyItem);

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Unchanged);
        }

        private AssemblyItem GetDetachedExistingAssemblyItem()
        {
            using (var bomContext = new BomContext())
            {
                AssemblyItem assemblyItem = bomContext.AssemblyItems.Find(3);

                return assemblyItem;
            }
        }
    }
}

Detach an Entity
To explicitly detach an entity from the DbContext we can either take the entity outside of the DbContext scope or call the Detach method on the ObjectContext under the hood of the DbContext.

using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Linq;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void DetachEntitySetStateToDetached()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();
            AssemblyItem assemblyItem = bomContext.AssemblyItems.First();

            ObjectContext objectContext =
                ((IObjectContextAdapter) bomContext).ObjectContext;

            objectContext.Detach(assemblyItem);

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Detached);
        }
    }
}

Using Entry
A much cleaner way of Adding, Removing, Attaching or Detaching an entity is by using the Entry method of the DbContext. It is smart enough to know to which DbSet the entity belongs and if the entity is already in the database or not (attach or add). You can set the current Entity State in one fell swoop as well. The example below shows an Attach operation and changing the state to ‘modified’.

using System.Data;
using System.Data.Entity;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void AttachEntitySetStateToUnchanged()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();
            AssemblyItem assemblyItem = GetDetachedExistingAssemblyItem();

            bomContext.Entry(assemblyItem).State = EntityState.Modified;

            Assert.IsTrue(
                bomContext.Entry(assemblyItem)
                    .State == EntityState.Modified);
        }

        private AssemblyItem GetDetachedExistingAssemblyItem()
        {
            using (var bomContext = new BomContext())
            {
                AssemblyItem assemblyItem = bomContext.AssemblyItems.Find(3);

                return assemblyItem;
            }
        }
    }
}

Entity Framework Concurrency Checking with Timestamp

Using a Timestamp column for optimistic concurrency control is quite a common practice in the SQL realm. While doing an insert, update or delete operation the database checks the Timestamp to see if the row has changed since the last time we retrieved it. If not the operation is canceled which eventually causes an exception to be thrown. Entity Framework supports optimistic concurrency checking with a Timestamp field out of the box.

In this example we use the AssemblyItem entity from the Bill Of Materials example. If we want to make sure we don’t save our edits over some other users changes, we need to implement some form of concurrency checking. In this case we do this by using the data annotation attribute Timestamp on the RowVersion property; a byte array.

using System;
using System.ComponentModel.DataAnnotations;

namespace CodeFirstPocos
{
    public class AssemblyItem
    {
        public int AssemblyId { get; set; }
        public int BillOfMaterialsId { get; set; }
        public string PartNumber { get; set; }
        public string Description { get; set; }
        public double Quantity { get; set; }
        public decimal Price { get; set; }
        public bool IsInStock { get; set; }

        [Timestamp]
        public Byte[] RowVersion { get; set; }
    }
}

This way Entity Framework knows we want to use the RowVersion property for optimistic concurrency control. If we let Entity Framework create our database we see a Timestamp column added to the AssemblyItem table named RowVersion.

Entity Framework Code First Concurrency Control RowVersion

Lets write a test to see optimistic concurrency checking in action. For this we need two different DbContext classes, retrieve the same entity, make some changes to both and call SaveChanges. Since we know the first row is already changed and stored in the database, the call to SaveChanges on the second DbContext for row2 should throw an exception of type DbUpdateConcurrencyException.

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        [ExpectedException(typeof (DbUpdateConcurrencyException))]
        public void ConcurrencyCheckingShouldFailIfTheSameRowIsEditedTwice()
        {
            const int assemblyItemId = 3;

            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext1 = new BomContext();
            var bomContext2 = new BomContext();

            AssemblyItem row1 = bomContext1.AssemblyItems
                .Single(ai => ai.AssemblyId == assemblyItemId);
            AssemblyItem row2 = bomContext2.AssemblyItems
                .Single(ai => ai.AssemblyId == assemblyItemId);

            row1.Quantity += 1;
            row2.Quantity += 10;

            bomContext1.SaveChanges();
            bomContext2.SaveChanges();
        }
    }
}

This test passed. So each time the test runs it throws a DbUpdateConcurrencyException when bomContext2 saves its changes. This is because the RowVersion column has changed after storing the edit in bomContext1. In the AssemblyItem table we see the expected incremental changes in the RowVersion column on every save.

Entity Framework Code First Concurrency Control RowVersion Data

Code First Fluent API Entity Type Configuration

Entity Framework let us use the Code First Fluent API in the DbContext to configure how your entities are created. This is done by using the modelbuilder in an override of the OnModelCreate method as explained here. A cleaner way of organizing your configurations is by deriving a custom class from EntityTypeConfiguration for each entity you need to configure.

In this example we configure the AssemblyItem entity from our previous example.

namespace CodeFirstPocos
{
    public class AssemblyItem
    {
        public int AssemblyId { get; set; }
        public int BillOfMaterialsId { get; set; }
        public string PartNumber { get; set; }
        public string Description { get; set; }
        public double Quantity { get; set; }
        public decimal Price { get; set; }
        public bool IsInStock { get; set; }
    }
}

By convention Entity Framework looks for an Id or classname + Id property to define the key for a specific entity. In our entity we want to use a different naming convention for our key property. We also want to change the name of the corresponding table column for the rather lengthy BillOfMaterialsId to BomId. Besides that we need to tell Entity Framework we don’t need to store the value of the IsInStock property, since it’s only used as a temporary value.

To do this we create a derived class named AssemblyItemConfiguration from EntityTypeConfiguration and set up the configuration in the constructor by using the Code First Fluent API.

using System.Data.Entity.ModelConfiguration;
using CodeFirstPocos;

namespace CodeFirstData
{
    public class AssemblyItemConfiguration
        : EntityTypeConfiguration<AssemblyItem>
    {
        public AssemblyItemConfiguration()
        {
            HasKey(ai => ai.AssemblyId);
            Property(ai => ai.BillOfMaterialsId)
                .HasColumnName("BomId");
            Ignore(ai => ai.IsInStock);
        }
    }
}

The only thing we need to do for this new Entity Type Configuration to work is to add it to the configurations collection of the modelbuilder in the OnModelCreating method of our DbContext derived class.

using System.Data.Entity;
using CodeFirstPocos;

namespace CodeFirstData
{
    public class BomContext : DbContext
    {
        public DbSet<BillOfMaterials> BillOfMaterialsSet { get; set; }
        public DbSet<AssemblyItem> AssemblyItems { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new AssemblyItemConfiguration());

            base.OnModelCreating(modelBuilder);
        }
    }
}

Lets write a simple test to see if this works…

using System;
using System.Collections.Generic;
using System.Data.Entity;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void AssemblyItemEntityShouldGetCustomConfiguration()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();

            var assemblyItem =
                new AssemblyItem
                    {
                        Description = "Screw",
                        IsInStock = true,
                        PartNumber = "S05-331",
                        Price = 12.50m,
                        Quantity = 4,
                    };

            var bom =
                new BillOfMaterials
                    {
                        CreationDate = DateTime.Today,
                        ProjectName = "AssemblyItem monster",
                        IsHandleWithCare = true,
                        AssemblyItems =
                            new List<AssemblyItem>
                                {
                                    assemblyItem,
                                },
                    };

            bomContext.BillOfMaterialsSet.Add(bom);
            bomContext.SaveChanges();
        }
    }
}

If we take a look in de database at the AssemblyItem table we see the expected key name is AssemblyId, the shortened version of the BillOfMaterialsId is now BomId and there is no IsInStock column.

Fluent Api Code First EntityTypeConfiguration Table result

Entity Framework Code First Database Creation Strategies

Lets talk strategy for a moment. By default the entity framework uses a database creation strategy called CreateDatabaseIfNotExists. As the name implies this database initializer only creates the database if it’s not on your SQL Express or by a connectionstring specified location.

Currently there are two more strategies to choose from; the somewhat harsh DropCreateDatabaseAlways and the more useful DropCreateDatabaseIfModelChanges. All these strategies have one big disadvantage in common. They trash your data relentlessly, so be careful what you ask for. To provide some initial data to play with while developing an model, we can override the Seed method of our custom strategy / database initializer.

In the example below we use the Code First model we’ve created in a previous example. We change the default database creation strategy with our custom database initializer derived from DropCreateDatabaseIfModelChanges. We also override the Seed method to initially fill the database with some useful data. So first we need to create our custom database initializer.

using System;
using System.Collections.Generic;
using System.Data.Entity;
using CodeFirstPocos;

namespace CodeFirstData
{
    public class DropBomContextIfModelChanges
        : DropCreateDatabaseIfModelChanges<BomContext>
    {
        protected override void Seed(BomContext context)
        {
            var bom =
                new BillOfMaterials
                    {
                        CreationDate = new DateTime(2012, 5, 18),
                        ProjectName = "The Code Project",
                        AssemblyItems =
                            new List<AssemblyItem>
                                {
                                    new AssemblyItem
                                        {
                                            PartNumber = "A1284-e",
                                            Description = "Case",
                                            Price = 199m,
                                            Quantity = 1,
                                        },
                                    new AssemblyItem
                                        {
                                            PartNumber = "124-448",
                                            Description = "Motherboard",
                                            Price = 398m,
                                            Quantity = 1,
                                        },
                                    new AssemblyItem
                                        {
                                            PartNumber = "i7-2600K",
                                            Description = "Intel i7 CPU",
                                            Price = 720m,
                                            Quantity = 1,
                                        },
                                }
                    };

            context.BillOfMaterialsSet.Add(bom);

            base.Seed(context);
        }
    }
}

To test this strategy we add a new boolean property to the BillOfMaterials poco named IsHandleWithCare.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace CodeFirstPocos
{
    public class BillOfMaterials
    {
        public int Id { get; set; }

        [MaxLength(24), Required, Column("Project")]
        public string ProjectName { get; set; }

        public DateTime CreationDate { get; set; }
        public List<AssemblyItem> AssemblyItems { get; set; }
        public bool IsHandleWithCare { get; set; }
    }
}

We write a testmethod to take this custom database initializer for a spin. We call the Database.SetInitializer method to provide it with our custom initializer. If we start using the DbContext while our model has some changes it will recreate and seed our database.

using System;
using System.Data.Entity;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void ModelChangeShouldCreateAndSeedNewDatabase()
        {
            Database.SetInitializer(new DropBomContextIfModelChanges());
            var bomContext = new BomContext();

            var bom = new BillOfMaterials
                          {
                              CreationDate = DateTime.Today,
                              ProjectName = "Important Project",
                              IsHandleWithCare = true,
                          };

            bomContext.BillOfMaterialsSet.Add(bom);
            bomContext.SaveChanges();
        }
    }
}

The database is created with our new IsHandleWithCare column.

Entity Framework Database Creation Strategy

The database is also seeded with our seed data from the custom database initializer.

Entity Framework Database Creation Strategy Rows

Entity Framework Code First Data Annotations

In the previous post we explored the use of the Entity Framework Code First Fluent API to configure properties and specify how the corresponding database is created. You can do this also by using data annotations. These are a set of configuration attributes found in the System.ComponentModel.DataAnnotations namespace. This post extends on the previous example, so if you haven’t read that one you might want to take a look first.

In this example we recreate the database we used in the previous example. We used the Code First Fluent API for configuring model creation. This time, however, we use data annotations to specify the same custom settings. We have a Bill Of Materials entity with a ProjectName property. We want this to be required, have a maximum length of 24 characters and change the column name in the database to ‘Project’.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace CodeFirstPocos
{
    public class BillOfMaterials
    {
        public int Id { get; set; }

        [MaxLength(24), Required, Column("Project")]
        public string ProjectName { get; set; }

        public DateTime CreationDate { get; set; }
        public List<AssemblyItem> AssemblyItems { get; set; }
    }
}

That’s all. Our DbContext derived class BomContext still has the two DbSet properties for BillOfMaterials and AssemblyItem without the override of the OnModelCreating method.

using System.Data.Entity;
using CodeFirstPocos;

namespace CodeFirstData
{
    public class BomContext : DbContext
    {
        public DbSet<BillOfMaterials> BillOfMaterialsSet { get; set; }
        public DbSet<AssemblyItem> AssemblyItems { get; set; }
    }
}

Lets create a test to verify this configuration with data annotations. We create a new Bill Of Materials with a ProjectName larger than the allowed 24 characters. We expect a DbEntityValidationException to be thrown, so we set the ExpectedException attribute of the testmethod accordingly.

using System;
using System.Data.Entity.Validation;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        [ExpectedException(typeof (DbEntityValidationException))]
        public void ProjectNameWithMoreThan24CharsShouldThrowException()
        {
            var bom =
                new BillOfMaterials
                    {
                        CreationDate = new DateTime(2012, 6, 29),
                        ProjectName = "The Data Annotation Project",
                        AssemblyItems = null,
                    };

            var context = new BomContext();
            context.BillOfMaterialsSet.Add(bom);
            context.SaveChanges();
        }
    }
}

If we run the test it passes so the DbEntityValidationException is thrown as we expected. The exception is thrown on the context.SaveChanges() method.

Entity Framework Code First Data Annotations Test

Finally lets see if the database got created the way we configured it with data annotations.

Entity Framework Code First Bom Context

And so it did… :-)

Code First Fluent API Entity Framework Model Creation

Since Entity Framework 4.1 we can use the Code First Fluent API to specify how our database gets created, effectively overriding the default settings. This is also possible with data annotations, but the Fluent API gives us a way to keep this out of our POCO classes and into the data layer.

In this example we have two POCO’s; first a Bill of Materials (BOM)…

using System;
using System.Collections.Generic;

namespace CodeFirstPocos
{
    public class BillOfMaterials
    {
        public int Id { get; set; }
        public string ProjectName { get; set; }
        public DateTime CreationDate { get; set; }
        public List<AssemblyItem> AssemblyItems { get; set; }
    }
}

… which can contain a list of assembly items.

namespace CodeFirstPocos
{
    public class AssemblyItem
    {
        public int Id { get; set; }
        public int BillOfMaterialsId { get; set; }
        public string PartNumber { get; set; }
        public string Description { get; set; }
        public double Quantity { get; set; }
        public decimal Price { get; set; }
    }
}

If we let Entity Framework create our database, we get default creation behavior which is not always what we want. For instance the string type gets translated to the database as a nullable varchar(max) column by default. Maybe we want to restrict the length of that property. Or maybe we use lengthy names for properties in our POCO classes, but we want shorter equivalents in the table. That’s where the Code First Fluent API comes into play.

With Code First we create a descendant of the DbContext class with a DbSet property for each POCO entity. The first time this DbContext gets instantiated it will create the database for us (if it’s not already there). During that process the OnModelCreating method gets called and that is the spot where we may provide different configuration using the Code First Fluent API.

In the BomContext class below we override the OnModelCreating method and specify the maximum length of the ProjectName property of the BillOfMaterials entity. We also tell Entity Framework to make it required and rename this property to ‘Project’ in the database.

using System.Data.Entity;
using CodeFirstPocos;

namespace CodeFirstData
{
    public class BomContext : DbContext
    {
        public DbSet<BillOfMaterials> BillOfMaterialsSet { get; set; }
        public DbSet<AssemblyItem> AssemblyItems { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<BillOfMaterials>()
                .Property(p => p.ProjectName)
                .HasMaxLength(24)
                .IsRequired()
                .HasColumnName("Project");
        }
    }
}

We create a simple test against SQL Express to see how Entity Framework creates our tables. We create one fictive Bill of Materials with three assembly items.

using System;
using System.Collections.Generic;
using CodeFirstData;
using CodeFirstPocos;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CodeFirstTests
{
    [TestClass]
    public class BomTests
    {
        [TestMethod]
        public void FirstCallToBomContextShouldCreateDatabase()
        {
            var bom =
                new BillOfMaterials
                    {
                        CreationDate = new DateTime(2012, 5, 18),
                        ProjectName = "The Code Project",
                        AssemblyItems =
                            new List<AssemblyItem>
                                {
                                    new AssemblyItem
                                        {
                                            PartNumber = "A1284-e",
                                            Description = "Case",
                                            Price = 199m,
                                            Quantity = 1,
                                        },
                                    new AssemblyItem
                                        {
                                            PartNumber = "124-448",
                                            Description = "Motherboard",
                                            Price = 398m,
                                            Quantity = 1,
                                        },
                                    new AssemblyItem
                                        {
                                            PartNumber = "i7-2600K",
                                            Description = "Intel i7 CPU",
                                            Price = 720m,
                                            Quantity = 1,
                                        },
                                }
                    };

            var context = new BomContext();
            context.BillOfMaterialsSet.Add(bom);
            context.SaveChanges();
        }
    }
}

We take a look at the database after we run the test method. Entity Framework created the database for us called CodeFirstData.BomContext. In the BillOfMaterials table we now have the required column ‘Project’ allowing a maximum length of 24 characters.

Entity Framework Code First Bom Context