How to reset Entity Framework Migrations back to square one? - postgresql

I have an asp.net core web api with a connection to a postgres db. I added a migration via dotnet ef cli and updated my database via:
dotnet ef migrations add initial
dotnet ef database update
There was no problem and I found my newly generated tables and the migration history in my schema. Then I messed up and did the same from a different project with a different name but with the same connection string. I used the same commands as above.
Now I cannot access neither the migration history table nor the generated tables anymore:
ERROR: must be owner of relation __EFMigrationsHistory
I wasn't able to get the rights for my migration history again.
How do I reset this to square one? Thank you in advance.

Related

Entity Framework Core deleting migrations?

I deleted all my migrations
I deleted my ModelSnapshot.cs
I deleted my database
I now run Add-Migration Init
I would expect a new migration containing all my models being created and applied in that single migration.
Instead i see the latest changes to the model.
Its clear there is some magic caching going on somewhere.
Where is this magic cache and how do I delete it?
Or do i have to delete the entire project and start over copying over my EF models?

Deploy EF code first using Azure Pipelines

I am using Entity Framework code first. I am able to update my database during development using Update-Database from Nuget Package Manager. Now I want to the database to be updated when building from my Azure Pipeline. Is there any documentation from Microsoft of this? How are others handling this?
(Not sure how much information you are looking for, so ask a follow-up/add a comment if this isn't enough.)
Server-side (e.g. in CI pipelines) as well as client-side, this can be done with the CLI instead of the VS specific package manager console:
dotnet ef database update --verbose
See Entity Framework Core tools reference - .NET Core CLI: dotnet ef database update for further information.
Generally, I would discourage anybody from automatically applying database migrations to a production environment.
Migrations should always be scripted to a file via dotnet ef migrations script, thoroughly checked and tested and only then be applied directly from this script (after creating a backup) to a production database.

EF Core Migrations - how to modify the previous migrations?

I have a question about editing migration files in EF Core.
Example: I have created 3 tables using separate migration for each: AddTable1, AddTable2, AddTable3.
After that several days later I decided to change the type of status column in Table1 to be int and not string.
After updating the AddTable1 migration file, deleting the database and executing update-database command the column was still defined with string type.
I noticed that all the .Designer.cs files still were using string type for status column despite my edit of Table1 migration file.
I copied the content of the AppDbContextModelSnapshot.cs file and manually updated all the .Designer.cs files for all migrations (note: the method name in source and .Designer.cs files is different).
And that helped. I'm sure that this is not the recommended way to use migrations.
My question is: is there a command which will do what I did - 'reset' the '.Designer.cs' files?
If not, how to make one? :)
Think of migrations as Git commits. You don't rewrite previous commits once you've shared them with other team members (or in our case, applied a migration to a database). Instead, you create new migrations with additional changes.
If you haven't applied a migration or shared it with teammates, you can remove it and re-scaffold:
Remove-Migration
Add-Migration FixedUpMigration
See the EF Core Migrations docs for basic usage.

How do I consolidate migrations using EF Core?

I have these migrations:
00000000000000_First
20161101000000_Foo
20161102000000_Bar
// ...many many MANY more
20161108000000_Baz
I want to consolidate from Foo to Baz into one new migration. I know how to do that in EF, but not in EF Core.
I tried this:
dotnet ef update database 00000000000000_First
// delete all other migration classes
dotnet ef migrations add Consolidated
dotnet ef update
I expect that the new Consolidated migration will contain all changes to the model. But its Up() and Down() methods are empty.
What am I doing wrong?
You're missing one step. Because of the new model snapshot, after you manually delete the migration files, you'll need to run dotnet ef migrations remove (or Remove-Migration in PMC) to get it back in sync.
Instead of manually deleting the files, you could also just run dotnet ef migrations remove multiple times, but it's smart enough to detect manually deleted migrations.
EF Core, when executing ef migrations add, does NOT look into real database. Only your code (and DB model snapshot in Migrations folder) is used.
So, you need remove migrations from your migrations folder (using dotnet ef migrations remove multiple times) and then create consolidated using ef migrations add.
About your real database - if you want to roll it back too, you should run ef database update XXX before removing migrations. Or, if you are collapsing all migrations - you can simple drop database completely and then recreate from new migration(s).

Consolidating EF migrations into new InitialCreate

I have been using EF migrations for some time now and have more than 100 migration files in my project. I would like to consolidate these into a single migration before moving forward - ie I want to replace the existing InitialCreate migration with a new version that takes all my subsequent changes into account so I can then delete all the other migration files.
I do this very easily if I am not concerned with losing all the data in the DB, but I am.
How can I achieve this whilst keeping all data intact and also retaining the ability to recreate the database from scratch (without data) by just running Update-Database (which I believe is not possible using the approach outlined by Julie Lerman)?
Consider reading this nice article from Rick Strahl :
https://weblog.west-wind.com/posts/2016/jan/13/resetting-entity-framework-migrations-to-a-clean-slate
Basically the solution is not trivial and needs more than just reseting all the migrations into one
because you have two scenarios that needs to fit in ONE migration class:
Create a new database => the migration class should contain every table creation
My database is already up to date => I need an empty migration class
Solution:
The idea of this process is basically this: The database and the EF schema are up to date and just the way you want it, so we are going to remove the existing migrations and create a new initial migration.
In summary, the steps to do this are:
Remove the _MigrationHistory table from the Database
Remove the individual migration files in your project's Migrations folder
Enable-Migrations in Package Manager Console
Add-migration Initial in PMC
Comment out the code inside of the Up method in the Initial Migration
Update-database in PMC (does nothing but creates Migration
Entry) Remove comments in the Initial method You've now essentially
reset the schema to the latest version.
once the commented out migration has been executed on the desired database, uncomment the migration code
If you're not concerned with keeping this migrations, what I've done is delete everything in your migrations folder, and then target a new database in the connection string (or pass in a new one). After that, you can just run the add-migration command:
add-migration InitialCreate
And it should create the migration for you.
Below procedure has the benefit of working without doing anything with the DBs, __MigrationHistory can stay as-is. Also it will work if you have multiple different environments with different versions of the structure - provided you have the branches to match.
I turn the last migration into an initial migration. The trick is to use the oldest version of the code and DB that is in use, replace its last migration with a new initial migration and delete all previous migrations. Newer branches keep the more recent migrations so those will still work after merging to older branches.
So start in the OLDEST branch - PROD, normally - and do:
Remove all but the last migration
Remove the migration code in both the "Up" and "Down" methods in the last migration
Change build action of the last migration to "None" to let EF ignore it
Change active connection to point to a local DB database.
Make sure this local DB database does not exist
add-migration Initial
Copy Up and Down code from the created "Initial" migration to the last migration
Delete Initial migration
Change build action of the last migration back to "Compile"
Check in
Merge changes up
Test in DEV branch on LocalDB DB - it should do the new initial migration as well as the subsequent ones with no issues
Test in main branch on the latest DB - it shouldn't do anything
Note above only works if you don't add stuff to the migrations that EF doesn't do itself. E.g. if you add DB views etc. than the newly created migration won't get those, it only gets the scripts EF generates based on your code.
Removing all migrations or regenerating them has drawbacks so we took an approach we merged all older migrations.
It require a bit of scripting. You read about the details here https://www.bokio.se/engineering-blog/how-to-squash-ef-core-migrations/ and see the scripts here https://github.com/bokio/EFCoreTools/tree/main/MigrationSquasher
The basic is the following steps though (copied from the blog post):
Overview of our approach
Create a new fresh database from the old migrations (We will use
this for comparison later)
Find a suitable target migration to be
the new initial (We picked one about 3 months old)
Write a script to
merge the Up() methods of all earlier migrations into the Up()
method of a new migration. We ignored Down() because we don't use it
for old migrations.
Generate this migration and add it to the
project. In our case we called it
20200730130157_SquashedMigrations1.cs. We used the snapshot from the
target migration we had picked.
Generate a 2nd prep migration that
inserts into the migrations history that
20200730130157_SquashedMigrations1.cs has already run. We called
this 20200730130156_SquashedMigrations1_prep.cs. Note the slightly
smaller timestamp on that one to make sure it runs before the real
migrations.
Delete the old migrations
Point our config to a new
database and run the migrations.
Compare that the schema we generate
is equal using the Sql Schema Compare in Visual Studio.
Work through
the issues until we have equal schemas. This part is a bit
complicated but I will get back to it.
Merge and 🤞 (Ok, we did run
more tests both on local and staging databases)
I hope this helps someone else. The EF team is looking at improving this story so if you have feedback on your requirements it probably help them to post that now https://github.com/dotnet/efcore/issues/2174.
We had the same problem.
The general solution we found was to
Archive the old migration / context on a Nuget Package (including dependancies and with a different namespace to avoid conflicts)
Delete all migrations and create a new Init (InitV2) Migration from scratch.
Change the startup sequence of our application:
If the database contains the first old Init migration then
Migrate the database using the Nuget Package to be sure it will be up to date
Then erase the content of the __EFMigrationHistory table and Insert the new migration in the table
After that use the standard Migrate method on the new context
That's it !
This solution is relatively simple. It solve all cases
New database (will be using the InitV2)
Old Database (will be upgrading to the last V1 Migration and after that to the last version of the v2 Database)
Be aware, if you used custom scripts/sql(...) in the v1 migrations, you have to check if the v2 Init migrations needs it.
To be sure it was OK, we created an empty database from v1 migrations and another one from v2 init migration and did a schema and data diff (with Visual Studio SQL Server Tools)