I have an assembly which contains two DbContexts both of which use EF Migrations generating explicit migrations with Add-Migration. I have a whole sequence of migrations on one datacontext, and (at the moment) a single migration on the other.
Looking through the code, I'm confused what exactly ties a given migration to the context and/or configuration that it affects. I see no references anywhere in the migration class, its auto-generated partial, or its resx of the "owning" configuration.
Related
I have a scenario where I deploy to different environments (development, testing and production), and each of these databases use different table name prefixes, along with different schema names.
Currently, in my CD pipeline I generate an idempotent script, and do string replacement on my 'variables' in my migration, however I'd like to utilize the dotnet ef database update command which makes it tricky as all my past migrations have been generated with a variable name within their table names, etc.
Is it possible that I can read from an environment file what that variable is while creating my DbContext and map/replace/infer what the actual table prefixes are when running the command line?
Edit 1:
To make matters a little more complicated, we're using an Oracle database
When generating our migrations, we have assistive functions that grant access to certain database users to view the newly added tables. These users too have different names per environment.
Reworking the users, table names, etc isn't in scope of this - I'm aware of the inefficiencies
Why don't you simply replicate the entire code?
When you scaffold/migrate you get partial classes, isn't it?
So, here the steps:
set the environment for Production, with a specific BUILD
variable
prepare the migration to the production database. You
will get at least the migration partial auto-class.
surround the entire body of the migration (having practically an empty file) within #if PRODUCTION ... #endif
rename the file with some _PRODUCTION suffix in the name. (it's partial class, it will be seen anyway)
prepare for DEVELOPMENT as in step 1.
migrate again, you will get again part of the partial class (the one that disappeared because the build variable changed.
surround everything with another #if DEVELOPMENT ... #endif and
change the file name suffixing it with _DEVELOPMENT.cs
loop unil you finish all your enviroments
do the same compiler selection for the variables holding the names of the users. You can be smart here, there should not be anything auto-generated in the class holding the users, so you can define that only class with parts of the names changing again with insertion/removals with #if and #endif.
I never happened to fall in such a weird case, but this would be the first solution I would try. The codebase is not growing as in any instant there is only one enviroment selected, the users get managed and EF can generate its automatic parts independently from your code.
Some side notes:
a sandbox or a clone of the database would be more suitable for testing. After you tested the development enviroment, will you test again the production one from scratch?
Changing the names of the users with just a prefix to differentiate the environment (without having all the details, I may not catch the full meaning of this) seems to bring small value to the effort of separation.
EDIT:
I don't change the previous text because it may drive you on theright path, but it is likely that you should not rename the migration file, otherwise the next migration will create anothe file with the base name. Just surround the entire migration class with the compiler directives, and let EF create another class in the same file at steps 2-3 and 5-6.
cheers
Alex
Without modifying too much your current flow you can do your string replacement before creating the migration and then, for each environment, use a different folder:
dotnet ef migrations add InitialCreate --context DbContext --output-dir Migrations/DevMigrations
dotnet ef migrations add InitialCreate --context DbContext --output-dir Migrations/ProdMigrations
But a cleaner approach would be: as you already know the differences between the various environments you could add that specific information in different db context and manage different DB schema/table names in the code itself of the dedicated DbContext. So in each DBContext you can put default schema name, link the entities to the correct table using a dedicated OnModelCreating and all the info that is different among the environments and then you can evolve each of these migrations:
dotnet ef migrations add InitialCreate --context DevContext --output-dir Migrations/DevMigrations
dotnet ef migrations add InitialCreate --context ProdContext --output-dir Migrations/ProdMigrations
To add the common relations/definitions that are the same for every environment you can use a dedicated IEntityTypeConfiguration to group your "business related" EF core configurations in a common place (the relations for example). This will avoid code duplication and let you have the "infrastructure related" EF core configurations defined in each dedicated DbContext (schema and table names), as they are actually different.
update To address the requirement to assign permissions you can add an empty migration where you can put sql scripts that perform whatever you need
So at the very end, in your pipeline, you can infer from the name of the stage/environment the name of DbContext and the folder where to save/fetch these migrations.
If you follow any of these approaches probably you will need to "sync" the already existing DB, see here and here,in the "Add your baseline migration" part
I have a .net core 2 project, along with Entity framework Core.
I have an existing database, and I've mapped them out to database entities in code.
The problem is that when I add a migration, expectedly it picks up my entity as a new table, however it is an existing table. The table shares the same name.
I suppose, I could just remove the contents of the Up method of the migration, but I want to know if there is a proper way instead of a workaround.
So, what I am asking is how can I tell entity framework core that this table is already existing?
EF 6 had an -IgnoreChanges option that would just take a snapshot with no Up() code, but that feature is not in EF Core (yet). See here.
If you comment out the Up() code as you have suggested that will indeed capture a snapshot of your existing objects and subsequent migrations will be incremental.
I have below structure of classes:
SecurityLayer.Domain dll
User class and some other classes
Has a nuget package for this
SecurityLayer.Data dll
SecurityDbContext class (which inherits from DbContext and manages User related entities
Has a nuget package for this
Now I build another product which uses two packages above. And I have below structure
MyProduct.Data dll has a ProductDbContext to manage entities from MyProduct.Domain dll
The problem is when I use Add-Migration on MyProduct.Data project, EF generates a migration to create ALL entities from both MyProduct.Domain and SecurityLayer.Domain
I know that EF6 support multiple DbContext in a single database, but it does not work for me. Can we do something to let EF avoid entities in SecurityLayer.Domain? Any advice is much appreciate. Tks a lot!
The easiest way would be to create your initial migration and remove the bits from it that are not relevant. Subsequent migrations will not pick up the existing tables due to the way EF works.
Migrations actually store the state of the database in a table called __MigrationHistory. One of those columns contains a zipped up EDMX file. You can extract the content as a blob, save it as a .zip file and see for yourself. Each migration uses that to determine what has changed since the previous migration.
I'm using EF6 code-first migrations for existing database but initial DbContext does not fully cover existing schema (since it's massive). So from time to time I have to make updates to the model in database-first style. For example when I need an entity mapping for a table or a column that is already in the database but not reflected in the code I do the following:
Make all change (add new entity, rename the column mapping or add new property)
Scaffold migration representing the latest model snapshot stub_migration
Copy-paste latest serialized model from stub_migration to the last_migration resource file
Delete stub_migration
Revert last_migration in database
Update-Database so that model snapshot in [__MigrationHistory] table would be also updated
I understand that this aproach is a bit hackish and the proper way would be to leave empty stub_migration but this would force lots of empty migrations which I would rather avoid.
Looking at a similar scenario from MSDN article (Option 2: Update the model snapshot in the last migration) I wouldn't imagine that there is an easier way rather than writing power shell script, managed code or both to make it work. But I would rather ask community first before diving deep into it.
So I wonder: is there a simple way to automate generation of new model snapshot in latest migration and reaplying it?
I'm doing something similar. I have a large database and I am using the EF Tools for VS 2013 to reverse engineer it in small parts into my DEV environment. The tool creates my POCOs and Context changes in a separate folder. I move them to my data project, create a fluent configuration and then apply a migration (or turn automigration on).
After a while I want a single migration for TEST or PROD so I roll them up into a single migration using the technique explained here: http://cpratt.co/migrating-production-database-with-entity-framework-code-first/#at_pco=smlwn-1.0&at_si=54ad5c7b61c48943&at_ab=per-12&at_pos=0&at_tot=1
You can simplify the steps for updating DbContext snapshot of the last migration applied to database by re-scaffolding it with Entity Framework:
Revert the last migration if it is applied to the database:
Update-Database -Target:Previous_Migraton
Re-scaffold the last migration Add-Migration The_name_of_the_last_migration which will recreate the last migrations *.resx and *.Designer.cs (not the migration code), which is quite handy.
Those 2 steps are covering 4 steps (2-5) from original question.
You can also get different bahavior depending on what you want by specifying the flags -IgnoreChanges and (or) -Force
And by the way, the major problem with the updating the DbContext snapshot is not how to automate those steps, but how to conditionally apply them to TEST/PROD environments depending on whether you actually want to suppress the warning because you've mapped existing DB-first entities in you DbContext or you want it it to fail the build in case you've created new entities and forgot to create a code-first migration for them.
So, try to avoid those steps altogether and maybe create empty migrations when you just want to map existing tables to your code.
I have changed my model and is scaffolding a new migration using the Add-Migration package manager command.
However, for some reason, EF think that I have been renaming an object for one of my classes. The class names are similar in name and have similar properties and relationships.
The problem is that the Update-Database command fails because of the rename. The very first command is RenameTable() and later on the migration tries to delete an index on the table that has been renamed (and doesn't exist anymore).
I would like to force EF to scaffold a migration where the old table is dropped and a new one is created instead. How do I achieve this? My impression was that EF can't be "smart" when figuring out renames and should always drop tables that are no longer mapped to an entity.