I have a problem.
Using Entity Framework code first and when merging code between branches we sometimes have to create empty migrations using
add-migration name -ignorechanges
The issue here is that a developer has created migrations on two different branches using the same name. They have different date stamps, so the file names don't conflict, but the generated class names are the same. Each migration has been applied to the databases on their respective environments.
I'm now merging the two branches together and, because the class names are the same, the project now won't compile.
No idea what to do. Any ideas please?
Thanks
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 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'm new to the Entity Framework. I've created a model-first schema in Visual Studio 2012 with EF5, but I'm having trouble getting the generated code to build. One of my entities ("Test") has the same name as the model (edmx) and the project (csproj) files, so it conflicts with the namespace (Test is a namespace but is used like a type). So I decided to change the namespace by setting a "Custom Tool Namespace" for the .tt files. This worked, but then I found that the "Test" entity's generated .cs file was entirely empty (other entities were generating properly), so I had build errors where other entities reference "Test". Renaming the entity results in a properly generated class, and therefore a building project, but I really want to use the original name.
I will probably end up scratching the project and starting over, ensuring to choose unique names for the project, the model, and the entity. But I'd rather know how to fix this if possible in case I run into something similar when the project is further along and it's not so easy to start over.
you can use use an alias on the Using Directive, e.g. using Project = PC.MyCompany.Project; to differentiate between namespaces. see MSDN
I have an application already in production using EF 5.0. I'm about to start on the next major revision. But before I do that, I'm trying to clean up a lot of my existing code.
One thing I want to change, is use a different class for one of my table entities. The new class is functionally identical to the previous. The only real difference is the name. E.g. ReceiptEntity will become Receipt.
This is to help simplify things, and stick to a simple naming convention.
However, EF Migrations are wanting to drop-recreate the table. This is not an option because the application is already in production. And I cannot allow for any data-loss.
Is there any way to change the Entity type without recreating the table that would make EF happy?
I was able to fix this by altering the generated migration.
The generated migration tried to create a table(one that already existed), then immediately drop it(which would of resulted in the data-loss).
I deleted all of the generated code, and simply 'Update-Database'ed an empty migration, and this solved the problem for me.