Hi Ian,
I can’t talk on best practices, but I can offer an example of how I’ve personally used Umbraco’s PackageMigrationPlan to add a custom tables using NPoco:
Here’s a link to the migration plan of my package, although it’s a very simple one, having only one migration step:
I’ve used the same technique in my client projects when adding custom tables.
As for your questions, I think I can answer two of them:
When implementing a concrete version of MigrationBase, should this class exist for the purpose of one single table or is it okay to bundle up an entire multi-table creation in this instance?
Personally, I have used a single MigrationBase implementation to manage multiple tables.
For example, this is what I have in a client’s project to manage custom Member tables:
public class CustomMemberTablesMigrationPlan : PackageMigrationPlan
{
public MigrationPlan() : base("CustomMemberTables") { }
public override bool IgnoreCurrentState => false;
protected override void DefinePlan()
{
From(string.Empty);
To<InitialMemberTablesMigration>("initial-member-custom-tables");
To<IncreaseAnswerVarcharSize>("increase-answer-size");
To<AddActivityLike>("add-member-activity-like");
To<AddDescriptionToFavouriteResource>("add-description-to-member-fav-resource");
To<UpdateFileUploadTable>("update-file-upload-table");
}
}
And the initial migration step creates all of the tables:
internal class InitialMemberTablesMigration : MigrationBase
{
protected override void Migrate()
{
if (TableExists("_MemberActivityStep") == false)
{
Create.Table<MemberActivityStepPoco>().Do();
}
if (TableExists("_MemberAnswer") == false)
{
Create.Table<MemberAnswerPoco>().Do();
}
if (TableExists("_MemberFavouriteResource") == false)
{
Create.Table<MemberFavouriteResourcePoco>().Do();
}
if (TableExists("_MemberFileUpload") == false)
{
Create.Table<MemberFileUploadPoco>().Do();
}
if (TableExists("_MemberProgrammeQuiz") == false)
{
Create.Table<MemberProgrammeQuizPoco>().Do();
}
if (TableExists("_MemberProgrammeSubChapter") == false)
{
Create.Table<MemberProgrammeSubChapterPoco>().Do();
}
}
}
The subsequent migration steps (MigrationBase implementations) where then added after the initial development, either during bugfixes or RFCs.
I tend to create a single PackageMigrationPlan per “feature” that requires custom tables.
No idea if this is the best way to do it, it’s just how me and my team have done it.
One of my tables needs to be hydrated with pre-existing look up data. Is there a preferred method? (I know of Execute.Sql( ) and Insert.IntoTable( ).)
You should be fine using whichever method suits your project/team.
Also, it’s worth noting that Umbraco has recently introduced the ability to use Entity Framework for database migrations instead of NPoco:
I hope that helps ![]()