Making a column sparse with Entity Framework Migrations

I have a database built off code first models, but I want to set some of the columns to sparse. There isn’t a way to this with the fluent api or through annotations. But it can be done with a migration.

There are plenty of articles that show how to run a migration so I will not cover that here.

Instead I’ll just show what you need to add to a new migration, I’m calling the migration MakeAddressSparse, and include the below code.

public partial class MakeAddressSparse: DbMigration
{
   public override void Up()
   {
      Sql("alter table dbo.Address alter column [Address1] varchar(100) sparse null");
      Sql("alter table dbo.Address alter column [Address2] varchar(100) sparse null");
      Sql("alter table dbo.Address alter column [Zipcode] varchar(10) sparse null");
   }

   public override Void Down()
   {
      Sql("alter table dbo.Address alter column [Address1] varchar(100) null");
      Sql("alter table dbo.Address alter column [Address2] varchar(100) null");
      Sql("alter table dbo.Address alter column [Zipcode] varchar(10) null");
   }
}

Drop down lists in ASP.NET MVC

This post shows two methods of implementing drop down lists in ASP.NET MVC 4. The code for data access and the general layout of the application should not be considered suitable for anything other than pedagogical purposes.

The provided source code uses entity framework and requires a local database to be running, see the web.config for naming.

The main components of the application are Vehicle and TyreType classes, and controllers for each.
The controllers have the standard Index/Create/Edit/Details/Delete views and actions.
The VehicleController shows two ways of providing a TyreType drop down list, one using the ViewBag and the other using a VehicleViewModel.

The TyreType is as follows.

using System.ComponentModel.DataAnnotations;

namespace Automobile.Models
{
    public class TyreType
    {
        public int TyreTypeID { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string Material { get; set; }
    }
}

And the Vehicle looks like this.

using System.ComponentModel.DataAnnotations;

namespace Automobile.Models
{
    public class Vehicle
    {
        public int VehicleID { get; set; }
        [Required]
        public string Name { get; set; }
        public string Description { get; set; }
        public double MSRP { get; set; }
        [Required]
        public int TyreTypeID { get; set; }
        public virtual TyreType TypeType { get; set; }
    }
}

The TyreTypeController is a standard controller with text boxes for entering information on the Edit and Create views.

The VehicleController has a drop down list filled with available tyre types as found in the database.

Using the ViewBag

The first method of filling the drop down list is to use the ViewBag.

In the [HttpPost]Edit method we have –

ViewBag.TyreTypeID = new SelectList(db.TyreType, "TyreTypeID", "Name", vehicle.TyreTypeID);

I’ll explain in detail what this line of code is doing –
ViewBag.TyreTypeID – is referencing the ViewBag and dynamically adding an entry called TyreTypeID.

new SelectList(db.TyreType, "TyreTypeID", "Name", vehicle.TyreTypeID) – is doing five things –

  1. new SelectList – creates a new SelectList(this is what drop down lists use)
  2. db.TyreType – passing in the TypeTypes from the database
  3. "TyreTypeID" – specifying that this public property of TyreType will be used for dataValueField
  4. "Name" – specifying that this public property of TyreType will be used for dataTextField
  5. vehicle.TyreTypeID – specifying the selected value in the drop down list, note that it is the same property as the dataValueField

Inside the TyreType Edit view we have –

@model Automobile.Models.Vehicle
…snip…
   <div class="editor-label">
      @Html.LabelFor(model => model.TyreTypeID, "Type Type")
   </div>
   <div class="editor-field">
      @Html.DropDownList("TyreTypeID","--Select a tyre type--")
      @Html.ValidationMessageFor(model => model.TyreTypeID)
   </div>

In this example the "TyreTypeID" specifies both the source of items for the drop down list and the destination property for the selected value that will be sent back to the controller. In the example, the Vehicle is sent to the Edit action, so the Vehicle. TyreTypeID is set with the selected value.

I found this very confusing at first because I wanted to change the name of the ViewBag property for storing the drop down list items, so my selected value was being lost. MVC is doing a lot by convention over coding, if you fight it you will have to learn many rules.

I’m not a big fan of this approach, too many things are happening without my explicit control and if forces me to use the same name for a list of items (the SelectList in the ViewBag) and the selected item (an int).

Using a ViewModel

One alternative is to create a ViewModel for the Vehicle and the values for the drop down list. Note again, I’m not advocating this methodology for data access for production code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Automobile.DataAccess;
using Automobile.Models;

namespace Automobile.ViewModels
{
    public class VehicleViewModel
    {
        private AutomobileContext db = new AutomobileContext();
        public IEnumerable<SelectListItem> TyreTypes { get; set; }
        public Vehicle Vehicle { get; set; }
        public VehicleViewModel(Vehicle vehicle)
        {
            Vehicle = vehicle;
            TyreTypes = PopulateTyreTypes();
        }
        private IEnumerable<SelectListItem> PopulateTyreTypes()
        {
            var tyreTypesQuery = db.TyreType.OrderBy(t => t.Name);
            return new SelectList(tyreTypesQuery,"TyreTypeID","Name");
        }
    }
}

Inside the VehicleController I have

public ActionResult Create()
{
   //we're going to use the view model to send the tyre types to the view here.
   var vehicleViewModel = new VehicleViewModel(new Vehicle());
   return View(vehicleViewModel);
}
   
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Vehicle vehicle)
{
   if (ModelState.IsValid)
   {
      db.Vehicle.Add(vehicle);
      db.SaveChanges();
      return RedirectToAction("Index");
   }
   var vehicleViewModel = new VehicleViewModel(vehicle);
   return View(vehicleViewModel);
}

And the view has

@model Automobile.ViewModels.VehicleViewModel
…snip…
<div class="editor-label">
   @Html.LabelFor(model => model.Vehicle.TyreTypeID, "Tyre Type")
</div>
<div class="editor-field">
   @Html.DropDownListFor(model => model.Vehicle.TyreTypeID, Model.TyreTypes, "--Select a tyre type--" )
   @Html.ValidationMessageFor(model => model.Vehicle.TyreTypeID)
</div>

@Html.DropDownListFor(model => model.Vehicle.TyreTypeID, Model.TyreTypes, "--Select a tyre type--" ) is doing three things –

  1. model => model.Vehicle.TyreTypeID – specifies where the selected value from the DDL is stored
  2. Model.TyreTypes – is the source of SelectListItems for the DDL
  3. "--Select a tyre type--" – is a default value

This is the approach I prefer. Full source code is a attached here.

Entity Framework in an Dynamics Nav (Navision) environment (or using EF to access tables with unknown table names)

Summary
In this post I should how to use dynamic compilation to allow Entity Framework to reference tables whose names are not known at compile time.

Details
Entity Framework works great for the majority of scenarios; it handles tables in one database or spread across multiple databases very well.  Let’s say you have a site that sells products online for small companies you would need tables like company, customer, order, product, invoice etc, you would probably put all your data into a single set of tables and EF will work just fine.

However, if you have ever worked Microsoft Dynamics Nav (Navision) you know that it does not follow this standard structure.

Dynamics segregates the data differently. Each company had its own set of customer, order, product, invoice, etc, tables which were prefixed with the company name. For example, if you had two companies called ACME and SuperCorp the table structure would be like the following –

[ACME$Customer]
[ACME$Order]
[ACME$Product]
[ACME$Invoice]
[SuperCorp$Customer]
[SuperCorp$Order]
[SuperCorp$Product]
[SuperCorp$Invoice]

EF does not play nicely with this.

My first attempt was to pass in the table prefix to my DbContext when mapping, this worked for the first company passed in, but when I create a new DbContext for the second company, it would give model errors because somewhere deep in the workings of EF, something was being set statically and the mapping was failing (it was still pointing to the first company). If I created another new DbContext for the first company it worked fine again.

My second attempt was to pass in a DbCompiledModel for the company when constructing  the DbContext

DbContext(string nameOrConnectionString, System.Data.Entity.Infrastructure.DbCompiledModel model)

This worked a bit better than the first attempt, I could create a DbContext for the first and second and first (again) companies. I could retrieve data, but as soon as a there was a join in the query it failed, again it looked like something was being set the first time I created the DbContext and this was not changing when for the second company. I wasn’t happy with this approach anyway as it required a significant step away from well known EF practices of mapping and constructing a context.
My third approach was to create a context file specifically for each company which would inherit from a base context that contained all the DbSets and column mappings, table mapping was done in each individual context. This approached worked for all database queries, but has the huge issue of requiring a recompile and redeployment for each new company; a working, but impractical approach.

Building on this I came up with my solution. I created a CommonDBContext, which has the DbSets and the OnModelCreating where the table prefix is passed to the Mapping classes.
A DynamicContext class that is used to dynamically compile and construct DbContexts for each of the companies as needed. It also caches the compiled DbContext so you only take the compilation hit once for the lifetime of the application.

public abstract class CommonDBContext : DbContext
{

private readonly string tablePrefix;

protected CommonDBContext(string connectionString, string tablePrefix) :base(connectionString)
    {
        this.tablePrefix = tablePrefix;
    }

    public DbSet Customer { get; set; }
    public DbSet Order { get; set; }
    public DbSet Product { get; set; }
    public DbSet Invoice { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new CustomerMap(tablePrefix));
        modelBuilder.Configurations.Add(new OrderMap(tablePrefix));
        modelBuilder.Configurations.Add(new ProductMap(tablePrefix));
        modelBuilder.Configurations.Add(new InvoiceMap(tablePrefix));
    }
}

class DynamicContext
{
    private readonly static Dictionary<string, Type> CompiledContexts = new Dictionary<string, Type>();
    private readonly string _classNamePrefix;
    private static readonly object LockObject = new object();
    private readonly string _sourceCode =
            @"
            using System.Data.Entity;
            namespace Implementation.Context
            {{
                public class {0}_Context : CommonDBContext
                {{
                  public {0}_Context(string connectionString, string tablePrefix)
                        : base(connectionString, tablePrefix)
                    {{
                        Database.SetInitializer<{0}_Context>(null);
                    }}
                }}
            }}";

    #region Constructors

    public DynamicContext(string classNamePrefix)
    {
        _sourceCode = string.Format(_sourceCode, classNamePrefix);
        _classNamePrefix = classNamePrefix;
    }

    #endregion

    #region Public Methods

    public CommonDBContext GetContext(string connectionString, string tablePrefix)
    {
        Type[] constructorTypes = new Type[2] { typeof(string), typeof(string) };

        Type compiledType;
        //Double lock to prevent multiple compilations of same code
        if (!CompiledContexts.TryGetValue(_classNamePrefix, out compiledType))
        {
            lock (LockObject)
            {
                if (!CompiledContexts.TryGetValue(_classNamePrefix, out compiledType))
                {
                    compiledType = CompileContext(_classNamePrefix);
                    CompiledContexts.Add(_classNamePrefix, compiledType);
                }
            }
        }

        CommonDBContext contextObject = GetInstanceOfCompiledContext(connectionString, tablePrefix, compiledType, constructorTypes);
        return contextObject;
    }

    #endregion

    #region Private Methods

    private CommonDBContext GetInstanceOfCompiledContext(string connectionString, string tablePrefix, Type compiledContext, Type[] constructorTypes)
    {
        ConstructorInfo contextConstructorInfo = compiledContext.GetConstructor(constructorTypes);
        object contextObject = contextConstructorInfo.Invoke(new object[] { connectionString, tablePrefix });
        return contextObject as CommonDBContext;
    }

    ///
<summary>
    /// This is a one time hit for each class compiled.
    /// </summary>

    /// <param name="assemblyNames"></param>
    /// <returns></returns>
    private string[] GetAssembly(string[] assemblyNames)
    {
        string [] locations = new string[assemblyNames.Length];

        for (int loop = 0; loop <= assemblyNames.Length - 1; loop++) { locations[loop] = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic && a.ManifestModule.Name == assemblyNames[loop]).Select(a => a.Location).First();
        }
        return locations;
    }

    private Type CompileContext(string classNamePrefix)
    {
        var compilerParameters = new CompilerParameters { GenerateInMemory = true };

        compilerParameters.ReferencedAssemblies.AddRange(GetAssembly(new string[] { "Implementation.dll", "EntityFramework.dll" }));
        var provider = new CSharpCodeProvider();
        var compiled = provider.CompileAssemblyFromSource(compilerParameters, _sourceCode);

        Type compliedType = compiled.CompiledAssembly.GetType(string.Format("Implementation.Context.{0}_Context", classNamePrefix));
        return compliedType;
    }

    #endregion

}

public class CustomerMap : EntityTypeConfiguration
{
    public CustomerMap(string tablePrefix)
    {
        // Primary Key
        this.HasKey(t => t.CustomerID);
        //snip

        // Map the table name
        string tableName = string.Format("{0}$Customer", tablePrefix);
        this.ToTable(tableName)
    }
}

If you have trouble getting this working, get in touch.