Can I delete an empty EF Migration safely - asp.net-mvc

I've just reviewed a colleague's work and there is an empty EF migration in his PR (up and down methods contain no code). There is another migration after this with DB modifications.
I believe that this empty migration can be deleted on the basis that it does absolutely nothing. There should be a corresponding entry in the _MigrationHistory table, which can also be deleted safely, in my opinion.
My colleagues believe that it should be left in there "just in case".
Are there any EF experts who can say which approach is best, and why?

Тhe truth is somewhere in the middle. You can delete it, but do not delete the migration file directly.
-> Removing A Migration
The following command removes a migration:
[Command Line]
dotnet ef migrations remove
[Package Manager Console]
remove-migration
You will use this command to remove the latest migration. This will remove the class file that was generated for the latest migration and it will also revert the ModelSnapshot file back to the state of the previous migration. If there are no pending migrations, an exception will be raised. If you want to remove a migration that has been committed, you must reverse the migration first (see below).
You should always use commands to remove a migration instead of simply deleting the migration code file, otherwise the snapshot and migrations will fall out of sync with eachother. Then future migrations will be based on a model that is incorrect. Nevertheless, the remove command will recognise if migration files have been deleted and will revert the snapshot accordingly.
If you need to remove a migration that was generated before the most recent one, you must remove all sunsequent migrations first, then adjust the model and then create a new migration to cater for the changes.
Sores: https://www.learnentityframeworkcore.com/migrations

Related

Reorder/change timestamp on migration files

One of my migration files is referencing another table/model that will will be created further down the migration sequence.
Postgres doesn't like that:
PG::UndefinedTable: ERROR: relation "users" does not exist
So I wonder if there are any potential problems to manually reorder the migration files (by inventing new timestamps/prefixes)?
The affected tables are already down migrated.
When you run rake db:migrate command it compares schema_migrations table and migration files located in db/migrate folder. All the migrations which were not executed receive MigrationClass#up call then.
So starting from the point when your code is already published and/or migrations are run by other users, changing your migrations timestamps/names may lead to unprocessable migration procedure (as schema_migrations will treat a migration with changed timestamp as new, unprocessed one, and try to process it "again"). Possible workaround for this would be to comment the contents of up method for a while and uncomment it back after migrations are done. For fun you can also manipulate schema_migrations table directly from your db console (adding or removing necessary records). Both of these ways smells like a hack though.
Until then... Everything should work flawlessly.
This is what worked for me for this same situation, even though it's a hack.
Rails runs migrations in order of the timestamp, and Rails tracks which migrations have been run by the timestamp part of the migration file name, but not by the rest of the file name. So if you need to change the order of two migrations because the earlier one references the later one you can simply switch the 14 digit timestamp portion of the filenames by renaming both migration files. If the timestamp is off by even one digit Rails will think it's a new migration so write them down before changing them.

Remove a column which was added recently

There was a time when I had to a column "column" to a model. Now I have to remove it. Is there any sensible method to that except a simple one by adding a new migration?
Depending on how deep down the rabbit hole you are you can rollback then delete the migration.
rake db:rollback
rails destroy migration *name of migration*
This will run the down method of the migration undoing the column add. The second command destroys the migration resetting your schema file.
EDIT:
Turns out your rabbit hole is deep. Best thing to do is to make another migration removing the column.
You can of course run SQL directly on the database. The problem with not using a migration file to perform this "subtle change" is that if you ever have to move your application to another server, you won't be able to recreate the database: this "column" column will be there because it's removal was never documented.
Stick with migrations!

migrate file timestamp

If I have two migration files:
20110414132423_insert_bulk_data.rb #1st
20111122105951_add_some_columns.rb #2nd
and I run rake db:migrate, is the 1st one run firstly since it has older timestamp??
Since I am in the middle of someone else's code, he made the 20110414132423_insert_bulk_data migration which insert data to table, but this migration file complains an unknown column in the table, then I found the missing column is defined in the 2nd 20111122105951_add_some_columns.rb migration file which has newer timestamp...
How can I get rid of this?
Shortly, yes. The timestamp is used to order migrations and to navigate between them. See more here
delete this migrations
generate two new migrations in the way you need to run

db:migrate has no effect

If I edit my shema, and run db:migrate the database doesn't changed, but if I clear to version 0, and recall migration it's works, but I lost all database data.
What's wrong?
That's how db:migrate works. It maintains a table in the database called schema_migrations that keeps track of the migration timestamps (i.e. if your file is called 20090807152224_create_widgets.rb, the 20090807152224 part is the timestamp -- and the line that will get added to your schema_migrations table).
You're not supposed to modify the schema.rb file by hand -- that file gets autogenerated as a result of db:migrate.
The thinking in rails is that if you want to make a change to your schema, you're going to generate a new migration with those changes and then run db:migrate (which, as a result, will update the schema.rb file appropriately).
When you say you are updating your schema, does that mean you're updating the db/schema.rb file, or actual migrations?
If you're updating the schema.rb file, you should note that it will have no effect because the file is auto-generated.
See the comment at the top of the file:
# This file is auto-generated from the current state of the database. Instead of editing this file,
# please use the migrations feature of Active Record to incrementally modify your database, and
# then regenerate this schema definition.
It sounds like you were changing a migration file.
Don't change migration files. Add new ones. You can have migrations that change say, the type of a column. There are times when changing old migrations may be helpful, but don't do it unless you know the consequences. As others have mentioned, don't change the schema either, but I don't think you were doing that.

Rails: Is the version number in 'schema.rb' used for anything?

Now that Rails has timestamped migrations, the single version number at the top of /db/schema.rb seems pointless. Sometimes the version number ends up incorrect when dealing with multiple developers or multiple branches.
Does Rails even utilize that :version parameter anymore?
And is there any harm in it being incorrect (as in: it doesn't reflect the timestamp of most recently applied commit)?
Example:
ActiveRecord::Schema.define(:version => 20100417022947) do
# schema definition ...
end
Actually, the version is much more important than this. The code you've cited is actually only a small part of what assume_migrated_upto_version does. The real effect of the migration version is that all prior migrations (as found in the db/migrate directory) are assumed to have been run. (So yes, it does what the function name suggests.)
This has some interesting implications, particularly in the case where multiple people commit new migrations at the same time.
If you version your schema.rb, which is what the Rails team recommends, you're okay. You're 100% guaranteed to have a conflict (the schema version), and the committing/merging user has to resolve it, by merging their changes and setting the :version to the highest of the two. Hopefully they do this merge correctly.
Some projects choose to avoid this continual conflict issue by keeping the schema.rb out of version control. They might rely solely on migrations, or keep a separate version-controlled copy of the schema that they occasionally update.
The problem occurs if someone creates a migration with a timestamp prior to your schema.rb's :version. If you db:migrate, you'll apply their migration, your schema.rb will be updated (but retain the same, higher :version), and everything is fine. But if you should happen to db:schema:load (or db:reset) instead, you'll not only be missing their migration, but assume_migrated_upto_version will mark their migration as having been applied.
The best solution at this point is probably to require that users re-timestamp their migrations to the time of their merge.
Ideally, I would prefer if schema.rb actually contained a list of applied migration numbers rather than an assume-up-to-here :version. But I doubt this will happen -- the Rails team seems to believe the problem is adequately solved by checking in the schema.rb file.
I decided to investigate myself. It turns out that because of the timestamped migrations, the only thing Rails does with that number is assume that the migration with that particular timestamp has already been applied and thus create the appropriate entry in the schema_migration table if it doesn't exist.
from: /lib/active_record/connection_adapters/abstract/schema_statements.rb
def assume_migrated_upto_version(version, migrations_path = ActiveRecord::Migrator.migrations_path)
# other code ...
unless migrated.include?(version)
execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
end
# ...

Resources