Migrate a MySQL Umbraco database to SQL Server
By: Sébastien Sougnez
Tags: Migration, MySQL, Sql Server, Umbraco

Introduction

The biggest breaking change introduced by Umbraco 8 is indubitably the end of the MySQL support. If, like me, you built a website using Umbraco and MySQL, this change must have annoyed you a lot especially considering that the Umbraco team didn’t not foresee any migration path.

As I didn’t want to be stuck using Umbraco 7 (especially considering all the awesome new features brought by Umbraco 8), I started to investigate a way to migrate my MySQL database to a SQL Server.

Fortunately, during my research, I found this post. So I decided to try and apply what’s said in it and it basically worked pretty well. However, I had to do a lot of extra steps but it looks like I finally managed to migrate the database. The goal of this article is to explain in greater details than this post how I achieved that and provide you with a migration path. Note that I tested this on only one web application built with Umbraco 7.14.0, however, as I’ll describe the way I used in details, you should be able to reproduce it with your Umbraco version.

Note that I’m no expert in SQL manipulations, so there might be a better or faster way of doing what I’m gonna explain. If there is, don’t hesitate to post a comment and I’ll try to update my post.

Finally, I’d like to thank one last time the author if the topic without who I wouldn’t have succeed in this migration.

MySQL and SQL Server

Before starting, ensure that you have a MySQL server and SQL Server one available for the migration. The EXPRESS version of SQL Server is enough.

SQL Server Migration Assistant

The first thing to do is to download and install the “SQL Server Migration assistant for MySQL” tool that allows you to migrate a MySQL database to a SQL Server one.

You could think that if such a tool exists, there is no big challenge in migrating the database. However, you’ll see that some stuff need to be corrected after the migration, such a some column types, or some constraints, etc…

Now, launch the tool and create a new project (File > New Project). Name and place it wherever you want but be sure to select to correct SQL Server version:

SSMA project creation

Click on “Connect to MySQL” to enter the connection settings to MySQL and validate.

MySQL connection settings

Select the database you want to migrate in the next screen:

MySQL database selection

Do the same for the SQL Server connection by using the button “Connect to SQL Server”.

SQL Server connection settings

Note that if the database does not exist, SSMA creates it for you. If, like me, you’re using SQL Express, you’ll probably have the following message:

SQL Agent warning

As “SQL Server Agent” is not available in the EXPRESS edition, you can’t start it but it’s not an issue as apparently, it works without it… So just ignore this warning by clicking “Continue”.

The database migration works in two steps: the schema needs to be converted, then the data need to be migrated. To migrate the schema, find your database on the top left part of the screen, right click on it and select “Convert schema”:

Schema conversion

You’ll probably see some errors in the log windows (bottom of the screen) but you can ignore them as we’ll fix them afterwards with our SQL script. Now, we need to synchronize the two databases to apply the schema to the target database. To do so, locate the target schema in the bottom left part of the screen, right click on it and select “Synchronize with database”:

Schema synchronization

The next screen just displays a summary of what’s going to happen, you can review it and then click on “OK”. Once the log “Synchronization operation is complete.” appears, you can start with the data migration.

To do so, locate your source database on the top left part of the screen and select “Migrate Data”:

Data migration

Once you validate, SSMA asks you to re-enter connections settings then starts the import.

Ensure that the summary screen only display 100% success rate:

Data migration summary

I never encountered a case where the success rate was not 100%, so I don’t know what to do if you have a different rate.

Creating a sane database

As I said earlier, the migrated database is mostly correct but not enough to work with Umbraco. Most error concern wrong data types, so we need to fix this. Doing so is a pretty repetitive task that could maybe be automated but I think the time taken to do so would be greater than the time taken to do so manually, so…

As we’ll need to compare every fields of every tables of the database, we need a sane database. To create one, just create a new Visual Studio project, install the Umbraco package corresponding to the version of the database to migrate, launch the site and complete the wizard. Once you’re done, you should have an empty Umbraco database that we’ll use to compare the schema.

SQL Script

Now, we’re going to write a SQL script that we’ll use to fix all the database differences. Once this script is done, you’ll be able to use it on whatever environment you want to automate the database migration if needed. Let’s start this script by using the target database (mine is called “umbracoprd01”):

The first issue I encountered is the fact that SSMA didn’t migrate the tables in the “dbo” schema, which is required by Umbraco to work. So the first part of the script consists in moving all the tables in this schema:

A big thank to the author of this post that helped me automate this.

Another issue concerns the constraints of the tables:

Constraints issues

As you can see by the name of these constraints, they have been created by “SQL Server” itself and don’t match the one of the sane database. The same goes for the “Keys”, so we’ll use the following script to drop all the constraints of all the tables:

Once again, a big thanks to the author of the answer of this Stack Overflow topic.

After the execution of this script, no constraint (default values, primary keys, foreign keys, etc…) exist anymore in the database.

The last thing to delete are indexes. Indeed, as we’ll need to update the type of some columns, we need to drop the indexes of all the tables to be able to do it. You can use the following script to do so:

Now comes the cumbersome part. Indeed, you need to compare every fields of every tables to ensure that their type and their nullable settings are correct. As you can imagine, this is a pretty repetitive task and you’ll see that as you progress from table to table, you’ll notice that the differences are always the same. Below, you’ll find all the differences I found in the columns settings for the version 7.14.0 of Umbraco (you’ll also find the final script I used for this version at the end of this post). Don’t hesitate to post a comment if you found more of them.

All the tables names are in lowercase, so “cmsContent” is actually “cmscontent”, so we’ll need to rename all the tables.

The “smallint” type is used while Umbraco expects “bit”.

The “nvarchar(36)” type is used while Umbraco expects a “uniqueridentifier”.

All fields supposed to be “uniqueridentifier” are set as “nullable” while most of them must be “not nullable” (you need to check this for all of them).

The “nvarchar(max)” type is used while Umbraco expects a “ntext”.

So now, your job consists in creating script like the one below:

The first line rename the table. You need to do this for every tables.

tables. The next five lines change the type of columns based on the rules listed above. Note that the “uniqueId” one is set as “NOT NULL”. To know that, you need to check the “null” settings of this column in the sane database.

Lines 7–11 add constraints for this table. Follow the explanations below to know how to find them.

Constraints can be exported from the sane database. To do so, expand the folder “Constraints” of the table in the sane database:

Constraints

And for each of them, right click on it and select “Script Constraint as” > “CREATE TO” > “Clipboard”, then paste the result in the main script. Do the steps described above for each table to get a working database.

Indeed, normally, the current state of the database is good enough for Umbraco to use it. However, it lacks the key constraints and the indexes, so in order to be as close as the sane database possible, we’ll need to export them as well.

We can start by the primary keys by expanding the folder “Keys” of all the tables of the sane database, right click on the constraints with a name starting with “PK_”, select “Script Key as” > “CREATE TO” > Clipboard and paste the result in your script. Hereunder, you’ll find an example of some of these keys:

The next thing to migrate are indexes. Indeed, you cannot create foreign keys on fields that are not unique, so we need to enforce this by creating the indexes. The steps to follow are exactly the same as the ones for primary keys, except that you need to expand the folder “Indexes” and export all of them not starting by “PK_” (as they concern the primary keys created before). Hereunder, you’ll find an example of some of these indexes:

We’re almost there… Now that we have exported the primary keys and the indexes, we just need to export the foreign keys. To do so, follow the same steps as for the primary keys, except that you’ll need to export the constraints starting by “FK_”. Hereunder, you’ll find an example of some of these constraints:

And here we are, we have a fully workable script used to fix all the differences (I found) between a sane database and the migrated one. You can find the one I used for Umbraco 7.14.0 here.

Custom tables

This script does not include the custom tables you could have created but the same differences apply to them, so don’t forget to also migrate them. However, as you don’t have these tables in the sane database, you cannot really compare them, but normally, as you’re owner of these, you should know their details. For my part, I had three tables and I could follow the instructions of this post to migrate them.

Conclusion

Following the steps described above, you should be able to migrate a MySQL Umbraco database to a SQL Server one. However, I just finished writing this script yesterday. I performed some basic tests (creating content, updating it, displaying it, etc…) and it seems to work but I (or you) might discover some issue, so I’ll perform some more tests and update this post if I found something to improve. Don’t hesitate to add a comment if you find something to improve.