EntityFramework Core production migrations - ef-code-first

How do I update the database for production? I've moved the connection string secrets out of the application. Our CI/CD pipeline handles the token replacement within the connection string "template" that remains in the appsettings, and developers won't have production database access.
I had expected to use automatic migrations, only to discover today that Microsoft eliminated that for EF Core.
Will I have to, every time, temporarily overwrite the connection string that normally specifies my local dev copy of the database? It seems that way, but it also seems very janky process to me, so I wonder if I'm missing something.

There seem to be a confusion of what automatic migration means.
Migrations consist of two parts:
generation from the model
applying to the database.
Migration generation in turn could be two types:
automatic - at runtime, current model is compared to model produced by the last migration, and if there are changes, it generates an automatic migration code.
manual - migrations are generated at design time using the design time tools (Add-Migration command). The auto-generated code can be modified. Modified or not, the migration is stored along with the application code.
Regardless of how migrations are generated, they can be applied at design time using the tools (Update-Database command) and/or at runtime.
What EF6 supports and EF Core have removed is the auto-generation. EF Core migrations cannot be generated at runtime - they must be generated at design time and stored with the application code.
Applying them at runtime is achieved with Migrate method called from some application startup point:
dbContext.Database.Migrate();
For more info, see Migrations and Apply migrations at runtime EF Core documentation topics.

Related

override database with new Migrations asp.net core

I created a new migration for my asp.net core Web API which applied the changes to my database, But I later deleted the migration manually. I now tried to add a new migration with new changes and but it is giving the error bellow since the changes from the migration I deleted were applied to the database already.
An error occurred while calling method 'BuildWebHost' on class 'Program'. Continuing without the application service provider. Error: There is already an object named 'FK_TaskDates_Tasks_TaskId' in the database.
Could not create constraint or index. See previous errors
Long story short, I'm trying to return the database state back to what it was before the deleted migration was applied.
Is there a way for me to revert the database back to it's working state?
Migrations work by comparing the new migration to the last one run. If there are no prior migrations, it will script out everything in the database.
Generally, for existing database with no prior migrations, you will need to add baseline migration. With EF6 you can use the -IgnoreChanges flag for this baseline. EF Core does not have that (unless recently added), so you can work around it by commenting out the stuff already in the database in the Up() method and applying it. The important thing is that a copy of the model is captured for future comparisons.
Now the next migration you add will only include the changes from that model stored in the code file.
To get your current system working, just comment out the stuff that already exists in the Up() method and keep the changed stuff and apply it (update-database).

Entity Framework 7 commands clarification - migrations add vs. database update?

I'm working on an ASP.NET 5 app that uses Entity Framework 7 with migrations to alter the application's Microsoft Sql Server database.
I'm running into a few issues when I reach the migrations step, and I would like clarification on what the Entity Framework commands migrations add and database update do.
It's my understanding that
> dnx ef migrations add Initial
creates a C# file ending in the name Initial in a folder named Migrations containing code that will create tables based on the application model classes, and
> dnx ef database update
executes the code that will add those changes to the database. However, after the migrations add command, the database has already been created, and the console gives an error when I run the database update command, saying that the tables already exist.
From what I've read on different tutorials, it seems like migrations add shouldn't actually affect the database, and the changes would take place when you run database update, but it doesn't look like that's the case.
Can someone explain what each of these steps are doing and how they fit together? Thanks in advance!
dnx ef migrations add shouldn't create the database. I suspect DbContext.Database.EnsureCreated() is being called somewhere in your application code giving it this effect.

Can EF Code First work with LocalDB in a ClickOnce application?

So, I'm trying out EF Code First, so that I can have the code drive updates to the database. I'm working on a ClickOnce app using LocalDB, so figured this may be the best solution for me, since otherwise changes to the MDF file will cause it to be overwritten on the client when deployed, thus losing everything entered before.
However, I'm now having my fair share of all new problems around Code First Migrations. I've followed through a Code First Migrations on MSDN, and I've managed to get the initial Configuration created, as well as the initial database creation.
The problems begin when I try to make my first actual migration. I added one single field to one of my models, and tried to make an explicit migration to handle that schema change for the next time I publish. Well...
PM> Add-Migration AddIsPercentField
Unable to generate an explicit migration because the following explicit migrations are pending: [201601052011180_InitialCreate]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
Ok... I'll run update and try again:
PM> Update-Database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201601052011180_InitialCreate].
Applying explicit migration: 201601052011180_InitialCreate.
Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.
You can use the Add-Migration command to write the pending model changes to a code-based migration.
PM> Add-Migration AddIsPercentField
Unable to generate an explicit migration because the following explicit migrations are pending: [201601052011180_InitialCreate]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
That's familiar, as that's the error (blatant lie?) it just told me earlier. Well, maybe if I undo my changes and update again, it will move to a valid state:
PM> Update-Database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201601052011180_InitialCreate].
Applying explicit migration: 201601052011180_InitialCreate.
Running Seed method.
Ok, no warning this time. Should be golden. Field added back, project rebuilt. Here we go:
PM> Add-Migration AddIsPercentField
Unable to generate an explicit migration because the following explicit migrations are pending: [201601052011180_InitialCreate]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
So... is there actually a working way to generate explicit migrations for any changes beyond the first?
EDIT: I made some forward progress on this, I believe. I did notice that the __MigrationHistory table was not generated in my .mdf after running Update-Database, even though it said everything completed just fine. I believe the issue is actually around how the local database works within the application. The connection string references AttachDbFilename=|DataDirectory|. What I think is going on is that it is deploying the .mdf temporarily, updating that temporary deployment, thus ultimately not committing the changes.
I'm working on a solution I have in mind, which is to have migrations work against a copy of the blank .mdf put in a static location, so that the static .mdf will be used to track and determine changes, while the blank .mdf will be what goes out to clients with the deployment.
I found that the root of my problem was that the console commands were not actually able to make changes, thus track migrations, to my data file. This was due to the connection string to the data file referencing a deployed location, so the file being updated was merely temporary.
This was in part a good thing, because the whole point of using Code First Migrations in my project was to avoid a hash signature change to my .mdf (which should have simply remained blank, as a placeholder) when publishing, so that the data from previous versions would never be overridden and discarded. However, that also introduced the obvious (in retrospect) problem that EF could not track changes due to there never being a __MigrationHistory table.
The solution upon which I arrived was to have two .mdf files. The blank one, for deployments, and a second one, to which I would interact with Code First Migrations. So, I have the initial MyData.mdf of Build Action Content, and a second MyDataDesignTime.mdf of Build Action None. (The "Design Time" migration database shouldn't be deployed.)
Using this approach, I found that I could now work successfully with migrations, calling Update-Database and Add-Migration, making sure to pass the -ConnectionString parameter with AttachDbFilename pointed to the full path to my design time database.
Later, getting lazy to supply a long -ConnectionString parameter on every migration command, I added the design time path to my config connection strings, and updated my DbContext so that it uses the design time path initially, but which I would change at the beginning of run-time to use my actual target data file:
public partial class MyData : DbContext
{
public const string DesignTimeConnection = "MyDataConnectionStringDesignTime";
public static string ConnectionName { get; set; } = DesignTimeConnection;
public MyData()
: base("name=" + ConnectionName)
{
}
...
}
And at application initialization:
MyData.ConnectionName = "MyDataConnectionString";
This works, and it makes things simpler on me. However, the one minor issue I'm left with is that I have a full static path which applies only to my environment left in the app.config file. Not currently an issue, as I'm the only dev on this project, but it's a code smell that I'm not happy with. Is there some path variable that I can use, such that it still points to the actual design time data (not any temporary, deployed file), but does so relative to the active, open project?

Best practice for using entity framework for post deployment database changes

I am working on a ASP.NET Web Forms project which is expected to experience lots of database changes even after deployment.
Our preference was to use Entity Framework 5, and the Database First design paradigm. However, since we have to make lots of changes to the database even after deployment, if I use database first approach, then every time I update my database, I will have to delete my entire model and regenerate it. Is there any best practices to make this process less painful?
You should use Code First, so that you can use Migrations.
More specifically I'd use manual Migrations.
With manual Migrations you can create Migrations at any point in time. A migration has the following information:
a snapshot of the current model
a set of "instructions" to upgrade from the previous migration
a set of "instructions" to downgrade to the previous migration
Apart from the necessary Migrations, you should add a new Migration when you deploy your app. For example, you can create a migration called "Version 1.0", when you deploy the version 1.0 of your app.
When you finish each new stable version, you simply add a new migration, for it, like "Version 1.1" or "Version 1.2".
The interesting part of migrations shows up when you have a deployed application version and you need to upgrade (or downgrade) to a new version.
There are commands that let you upgrade (or downgrade) a DB from one particular version
to another particular version. You can do it directly specifying a connection to the DB, or create a SQL script which will apply the changes to the DB. For example, if you deployed the version 1.0 in a customer server, and you need to upgrade the software to version 1.2, you can do this:
Update-Database -SourceMigration "Version 1.0" -TargetMigration "Version 1.2"
-Script
This will create a SQL script which can be run on the DB to upgrade from version 1.0 to 1.2.
If you need help about any of the Migrations commands, simply type:
get-help Update-Database -full
(Update-Database is a command name, you can specify any other like Add-Migration)
It's possible that you need to specify the project where the model is in, the connection string name, the name of the project with the .config file or some other things, depending on the specified parameters, and the structure of the projects in your solution.
To get more info on migrations, read MSDN EF Code First Migration.
NOTE ADDED IN EDITION: there is a new DB initializer that can automatically migrate to the latest version when the application runs. I've worked in a real application, and it works like a charm.
ALTERNATIVE SSDT
If you don't want to follow the advice, you can use SQL Server Data Tools (which can be installed inside VS, or work as an independente application, depending on the version you're using).
The idea of this tool is that you can compare projects (which are DB schema snapshots) to existing DBs, and generate the scripts to change the DB to match the schema in the project. (In fact you can compare any combination ofr project and DB)
If you keep versions of your project in a CVS you can even check the changes from one verison of the project to other version of the project.
NOTE ADDED IN EDITION: a SSDT project is a set of scripts that can build the whole DB, including all the objects in its schema. You can create it from an existing DB or viceversa. Then you can keep comparing any combination of DBs and SSDT projects, as soruce or target, and create an apply the scripts neccesary to change each particular object which has changes. (The scripts are created to change the target so that it looks like the source, but you can swap source and target easyly)
This is an alternative solution, but Migrations are much more powerful because you can customize them, for example to fill a "master table" when creating it, to set the initial value of a new column, and so on. If you use SSTD you'll have to do all of that by hand, and carefully keep track of it. So I highly recommend using Migrations.

Null reference to DataContext when testing an ASP.NET MVC app with NUnit

I have an ASP.NET MVC application with a separate project added for tests. I know the plusses and minuses of using the connection to the database when running unit tests, and I still want to use it. Yet, every time when I run the tests with the NUnit tool, they all fail due to my Data Context being null. I heard something about having a separate config file for the tests assembly, but i am not sure whether I did it properly, or whether that works at all.
i think you should check this discussion here, it should be related as i was having the same problem.
and how i solve my problem was just to copy my web config content to the app config inside he test project and voila, database connection restore and all is fine in the land of mvc again.
How are you creating your data context? How is it used in your action? Typically, it will use the database referred to when you set up the classes in the designer so you'd get a context connected to what you used for the designer which is, arguably, not what you want for unit tests, thus you add an app.config file to your unit test project and change the connection string to your test database. It doesn't usually result in a null data context.
I suspect that your unit test is simply not touching the code that creates the data context before you invoke the action method. Without code though, it's really impossible to tell.

Resources