-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added documentation for flattening migrations #47
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.Migrations; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace AndcultureCode.GB.Infrastructure.Data.SqlServer.Migrations | ||
{ | ||
public partial class FlattenedMigration : Migration | ||
{ | ||
public const string InitialMigrationId = "20200603183650_InitialCreate"; | ||
|
||
public static readonly List<string> FlattenedMigrations = new List<string> { | ||
InitialMigrationId | ||
}; | ||
|
||
#region Private | ||
|
||
GBApiContext _context; | ||
|
||
#endregion Private | ||
|
||
#region Overrides | ||
|
||
protected override void Up(MigrationBuilder migrationBuilder) | ||
{ | ||
} | ||
|
||
#endregion Overrides | ||
|
||
public GBApiContext Context | ||
{ | ||
get | ||
{ | ||
if (this._context == null) | ||
{ | ||
this._context = new GBApiContext(); | ||
} | ||
|
||
return _context; | ||
} | ||
} | ||
|
||
public bool ValidateFlattenedShouldRun(string id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick - alphabetization of methods |
||
{ | ||
int count = 0; | ||
using (var connection = Context.Database.GetDbConnection()) | ||
{ | ||
connection.Open(); | ||
|
||
using (var command = connection.CreateCommand()) | ||
{ | ||
command.CommandText = $"SELECT COUNT(*) FROM [dbo].[__EFMigrationsHistory]"; | ||
string result = command.ExecuteScalar().ToString(); | ||
|
||
int.TryParse(result, out count); | ||
} | ||
} | ||
|
||
// If we have migrations after this one (this isn't a new DB), then abandon ship. | ||
var migrationPosition = FlattenedMigrations.OrderBy(e => e).ToList().FindIndex(0, e => e == id); | ||
if (count > migrationPosition) | ||
{ | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public void LogMigrationMessage(params string[] messages) | ||
{ | ||
LogMigrationMessageLine(""); | ||
LogMigrationMessageLine("------------------------------------------------"); | ||
foreach (var m in messages) | ||
{ | ||
LogMigrationMessageLine(m); | ||
} | ||
LogMigrationMessageLine("------------------------------------------------"); | ||
LogMigrationMessageLine(""); | ||
} | ||
|
||
public void LogMigrationMessageLine(string line, string direction = "Up") | ||
{ | ||
var migrationName = this.GetType().Name; | ||
Console.WriteLine($"[Migration::{migrationName}#{direction}] {line}"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Flattening Migrations | ||
|
||
1. Checkout greatest common denominator brach -- typically `master`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Switch 'master' to 'main' |
||
a. Master has migrations run on `master` and any additional mainline branches downstream, while development would have migrations that have not yet been run on anything upstream of `development`. Therefore, choose `master`. | ||
2. Revert your database to the most recent flattened file, and delete all migrations other than the existing flattened migrations. | ||
3. Create new migration -- this migration will now include everything to get the database to the state it was in after applying every migration you just deleted. Important: This does NOT include any changes manually made to the migration files! | ||
4. Stash your changes and checkout the branch you'll be working off of (should be a branch off of the least common denominator branch, for example `development`). | ||
5. Pop the changes from your stash. You should now have your flattened migration for everything that had made it's way to `master`, as well as additional migrations that haven't yet made their way into `master`. | ||
6. EFCore uses string sorting to apply migrations in order -- thus the timestamp prepended to every migration you create. In this case, it will likely be at or near the end of the list, but we want to move it up to the top of the list to ensure it's run first. | ||
* In order to do this, open the flattened migration and ensure it extends `FlattenedMigration` instead of `Migration`. | ||
* In the `FlattenedMigration` class, add a new const for the ID of this migration. It should, when sorted as strings, be next in line from the previous flattened migration. Additionally, add it to the static list that contains all the migration ID consts. | ||
* Open the `Designer.cs` file of the flattened migration, and update the name in the `[Migration("")]` attribute to use the const you just added. | ||
* Rename the files themselves to match what you put in the `[Migration("")]` attribute. | ||
7. Manually update the flattened migration to call `ValidateFlattenedShouldRun` passing in the ID of the migration you are working off of. This will check if, based on the sort order of the other flattened migrations, this flattened migration has not run on a fresh install. If that method call returns false, you should abort running the flattened migration, as it means this is not a fresh install. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can some subset of this comment be added as a comment above the method in that base class? |
||
8. The final step, is to go back to `development` and take a glance at everything you just flattened to ensure there hasn't been any manual changes to migrations -- SQL being run directly, data manipulation, etc. -- and if there are, take those changes and create a new empty migration to ensure everything is consistent when the migrations are run. This migration should follow steps 6-8 in order to sort the migration correctly and validate it needs to be run. | ||
9. Test, test, test! Verify that everything works as expected when running against your local database (and, if you have a production backup on your machine, test that it works against that as well). Additionally, test that it generates a fresh database successfully, and that all your integration tests against that fresh database run successfully. | ||
10. Finally, be aware that it's possible your new flattened migration will cause people that haven't run the project for a while to be missing migrations when they start up the project. Let your team know this is the case so everyone has a chance to run `./sdk refresh-environment` on their machine before your flattened migration is merged in. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! What are your thoughts on migrating this to the Data.SqlServer package? I set it up this morning being I know we are going to need it. One of our clients could actually use this soon as it is on their backlog. https://github.com/AndcultureCode/AndcultureCode.CSharp.Data.SqlServer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps projects could extend this, being required to override specific aspects and 'context' be a generic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for switching gears on your in terms of OSS packages - if you don't have time, we can just create a github issue do to it later on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should be able to migrate this over on Friday. Once I do that, I'll also update this repo to use that package (I'll also address the
master
vsmain
issue when I migrate this over).