Can EF Code First work with LocalDB in a ClickOnce application? - ef-code-first

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?

Related

EntityFramework Core production migrations

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.

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).

MigrateDatabaseToLatestVersion seed() doesn't create tables in database [duplicate]

In my application I enable Code First Migrations with some migrations, Also I use SQL Server Compact for integration test.
When I run my tests, Entity Framework create an empty database and tries to run migration on that empty database and thrown The specified table does not exist.
Based on this report I think usage of Migration in Entity Framework 6 has changed.
I test all Database Initializer with Context.Database.Create(); but in all case tabale's never created.
I don't know that this is EntityFramework's bug or not, but when I made rename the namespace of Migration Configuration class from default (Projectname/Migrations) to any none default name, migration works well.
Context.Database.Create() will not execute migrations! It only creates empty db. To Update database from code to latest version you need to use DbMigrator.Update method:
var migrator = new DbMigrator(new MyMigrationsConfiguration());
migrator.Update();
Alternatively you might use MigrateDatabaseToLatestVersion
Database.SetInitializer(new MigrateDatabaseToLatestVersion<BlogContext, Configuration>());
It is described in details here: http://msdn.microsoft.com/en-us/data/jj591621.aspx#initializer
In case someone still struggles to fix the issue.
The code that follows works for me: add-migration MyFirstMigration
Meanwhile add-migration "MyFirstMigration" with the migration name ramped in quote doesn't work.
There may be previous migration files which the ide may be referring to mostly likely due to caching.
Drop backup and drop target database if it exists, and drop the migration folder.
Now add the migration and you will be good to go.
It does happens when adding model and running add-migration command.
Here is the simplest cause of this issue:
Add a newly added model property into IdentityDbContex class.
Here are the steps:
create model
add property into IdentityDbContex class
run add-migration
update-database

Do code first migrations use a transaction?

We are using Code First migrations and apply them using DBMigrator.Update() from our Application_Start event. Recently when deploying a new migration we got the following exception in from Application_Start:
PK_dbo._MigrationHistory'. Cannot insert duplicate key in object
'dbo._MigrationHistory'. The duplicate key value is
(201312020928218_ModifyReport)
This suggest that 1) Application_Start ran more than once and 2) code first migrations do not use a transaction to prevent the same migration being attempted multiple times. If that is so should we move migrations out of the appplication completely and include as part of deployment instead?
Code First migrations do not use transactions.
I guess you could customize migrations to use them, at least in EF6.
I'm kinda battling with similar issues myself at the moment.
Other than that I would put the update as part of the deployment rather than it being part of the app.

Can you create a database without migrations in EF5?

I am following the offical asp.net "Getting started with EF 5 using MVC 4". In that tutorial, the database is created when the migrations are performed(in my understanding). When I was looking at the EF 5 with Mvc 5 tutorial they didn't use migrations to create a database. They use database initializer. So, I was wondering could create a database for your project without using migrations in EF 5? Also, what would the difference be with both these approaches?
Code first Migrations and using Package Manager Console Commands to do upgrades can get a bit confusing at first.
You can use the initializer to CreateDatabaseIfNotExists , DropCreateIfModelChanges, DropCreateDatabaseAlways and to MigrateDatabaseToLatestVersion
See the interface IDatabaseInitializer<TContext>.
CreateDatabaseIfNotExists // is the Default initializer.
So this is why it appears EF just does things for you sometimes.
So the answer is "YES you can "Create a Database without Migrations"
But the difference is not obvious and if you would do that long term is another question.
If you are using migrations. It would Update the Db to match the code first model.
If there is NO database, then that means creating the database.
So Thats why Automated migrations and CreateDB look confusing since they can result in same outcome sometimes. But technically they are different.
So generally it is sufficient to use code first automatic "migrations" only.
Migrations can be either Automatic or "managed".
The managed migrations approach invovles generating code , tweaking the code and running PM commandlet or POwershell command to actually perform the migration.
With Automated migrations you just need set the intitializer and Access the DBContext.
There are 2 parts to the process.
a) The DB Initializer step.
do this immediately before instantiating YourDBContext.
//eg
// DONT TOUCH MY DB or i break your back!
Database.SetInitializer(new ContextInitializerNone<YourDbContext>()); // Do Nothing,
// OR
// yes migrate my db to match my code please.
Database.SetInitializer(new MigrateDatabaseToLatestVersion<YourDbContext, YourMigrationConfiguration>()); // Set to migration is requested, see config class below
The Confirguration class specified when using Migration initializer looks like this
public class YourMigrationConfiguration<TContext> : DbMigrationsConfiguration<TContext>
where TContext : DbContext{
protected YourMigrationConfiguration() {
AutomaticMigrationsEnabled = true; // run it when needed. Do not wait for my PM Command
AutomaticMigrationDataLossAllowed = true; // if the new db look means dropping tables or columns go ahead and kill my data. So use this option with caution.
}
then just trigger the migration in code when required.
Context.Database.Initialize(true); // i place this inside a method on my UoW class
Code first Db initialization strategies.
Code first migrations recommended reading
Managed Migrations
There are many articles on the web on this topic.

Resources