Customizing Code First Migrations Provider

Posted on January 16, 2012. Filed under: Entity Framework, Visual Studio | Tags: , , , , |

Code First Migrations is included as part of Entity Framework starting with the EF 4.3 release.

One feature we haven’t really blogged about yet is the ability to include additional arguments in a migration operation. These arguments are then made available to the SQL generator. You can then derive from the SQL generators that we ship, and customize the generated SQL based on the arguments you specify.

I’m going to assume you have a working knowledge of Code First Migrations… if you don’t, take a minute to read the Code-Based Migrations Walkthrough.

 

The Scenario

Code First Migrations allows you to add additional indexes to your database from within a code-based migration. These indexes are always ascending though… and you may find yourself wanting to add descending indexes. In this post we’ll look at extending the existing SQL Server generator to handle this scenario.

 

Specifying Additional Arguments

All the migration operation APIs, that are exposed in a code-based migration, include an optional anonymousArguments parameter. This parameter allows you to specify some additional arguments that should be stored in a property bag on the operation.

The additional arguments are specified using anonymous type syntax. The values are converted into a Dictionary<string, object> that is made available during SQL generation.

To specify the sort order of an index we are going to use the SortOrder key. When we create an index we’ll assign either “Ascending” or “Descending”. We’ll write the SQL generator so that it assumes an ascending index if the SortOrder isn’t specified.

Here is an example of the code we could write in a code-based migration:

CreateIndex(table: "Blogs", column: "Title", anonymousArguments: new { SortOrder = "Descending" });

 

Customizing the SQL Generator

Now it’s time to customize the SQL generator for SQL Server, so that it reacts to our custom argument. We can create our own generator that derives from the existing SqlServerMigrationsSqlGenerator. The generator is structured so that it’s easy for you to override just the operations you want to customize the SQL for. In our case we just want to change the SQL that is generated for a CreateIndexOperation .

using System.Data.Entity.Migrations.Model;
using System.Data.Entity.Migrations.Sql;
using System.Linq;

namespace CustomMigrationsProviders
{
    public class CustomSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
    {
        protected override void Generate(CreateIndexOperation createIndexOperation)
        {
            using (var writer = Writer())
            {
                writer.Write("CREATE ");

                if (createIndexOperation.IsUnique)
                {
                    writer.Write("UNIQUE ");
                }

                writer.Write("INDEX ");
                writer.Write(Quote(createIndexOperation.Name));
                writer.Write(" ON ");
                writer.Write(Name(createIndexOperation.Table));
                writer.Write("(");

                // Calculate sort order
                object sortOrder;
                createIndexOperation.AnonymousArguments.TryGetValue("SortOrder", out sortOrder);
                var sortOrderSql = sortOrder != null && sortOrder.ToString() == "Descending"
                    ? "DESC"
                    : "ASC";

                // Specify columns, including sort order
                writer.Write(string.Join(",", createIndexOperation.Columns.Select(c => Quote(c) + " " + sortOrderSql)));

                writer.Write(")");
                Statement(writer);
            }
        }
    }
}

The code inside the overridden Generate method if basically a copy/paste of the code in the base provider. The only customization is to the code that generates the columns to be included in the index. The customized code reads the anonymous arguments on the CreateIndexOperation and calculates the SQL operator to specify the sort order. This operator is then added to each column in the generated SQL.

Here is an example of the SQL that will be generated:

CREATE INDEX [IX_Title] ON [Blogs]([Title] DESC)

NOTE: You may notice that the code makes use of the Writer method to get a text writer to use for building the SQL. This isn’t mandatory, you can use any approach you want to create the SQL. The SQL you generate must be registered with the Statement method to ensure it gets executed.

 

Registering the Customized Provider

Now that you have a custom provider it’s time to let Migrations know to use your new provider, instead of the default, when running against SQL Server. You do this in the constructor of your migrations configuration class, using the SetSqlGenerator method. SQL generators are registered based on the provider invariant name of the database provider they generate SQL for, for SQL Server this is “System.Data.SqlClient”.

public Configuration()
{
    AutomaticMigrationsEnabled = false;

    SetSqlGenerator("System.Data.SqlClient", new CustomMigrationsProviders.CustomSqlServerMigrationSqlGenerator());
}

 

Summary

In this post you saw how to add additional arguments to a migration operation using the anonymousArguments parameter. You then saw how to customize the existing SQL Server generator to generate different SQL based on these arguments. Finally you saw how to register your custom generator so that Code First Migrations will use it in place of the default SQL Server generator.

Advertisement

Make a Comment

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 )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

4 Responses to “Customizing Code First Migrations Provider”

RSS Feed for RoMiller.com Comments RSS Feed

Rowan,

This is great! In this example, though, in order to slightly modify the behavior of an existing operation, we basically have to re-implement the existing behavior of the operation accurately, then make our changes. As far as I know, the source code for Migrations isn’t publicly available, so it would be difficult to duplicate the existing behavior. Do you have any suggestions for getting around this?

Hi Brian,
We tried to keep the methods you can override very granular, so you duplicate as little logic as possible. You can always use something like Reflector, dotPeek, etc. to see how implemented the method too.

Rowan,

I didn’t want to mention decompilation because I wasn’t sure if you guys would be cool with that. ;-) If that approach is on the up-and-up, my concerns are addressed. Thanks!

Hi,

This is nice but how can i use this on database creation. Is there a way to override Fluent Api to use the Anonymous Arguments?

I did a change for generate newsequentialid instead of newid but would be better to have a parameter.


Where's The Comment Form?

    About

    Rowan works as a Program Manager for the ADO.NET Entity Framework team at Microsoft. He speaks at technical conferences and blogs at http://romiller.com. Rowan lives in Seattle, Washington with his wife Athalie. Prior to moving to the US he resided in the small state of Tasmania in Australia. Outside of technology Rowan's passions include snowboarding, mountain biking, horse riding, rock climbing and pretty much anything else that involves being active. The primary focus of his life, however, is to follow Jesus.

    RSS

    Subscribe Via RSS

    • Subscribe with Bloglines
    • Add your feed to Newsburst from CNET News.com
    • Subscribe in Google Reader
    • Add to My Yahoo!
    • Subscribe in NewsGator Online
    • The latest comments to all posts in RSS

    Meta

Liked it here?
Why not try sites on the blogroll...

Follow

Get every new post delivered to your Inbox.

Join 25 other followers