EFCore Framework Scaffolding overwrites DBContext file - c#

I am trying to leverage scaffolding for EntityFrameworkCore to create an entity framework models for existing Sql Server database. This works fine and it did create the context file and all the tables.
However going forward I still want to continue to update the DB and get the model updated based on Database changes. This works fine with force flag on Scaffolding as it overwrites the tables with new changes.
The main concern I have is scaffolding needs db connection string which gets included in the DBContext file. And on running scaffolding command this file gets overwritten as well. Ideally i would like to save it in config file and have different value based on environments. However this means every time model is updated all my config changes are lost and I need to manually reapply the same
Is there any efficient way to do the same?

Use EF Core Power Tools, and the use the constructor that takes a DbContextOptionsBuilder and specify the privider and the corresponding connection string outside the DbContext class.

Related

How to re-seed database?

I am creating some web app using ASP.Net Framework Core and Entity Framework Core.
I have created local database using entity framework core, I have seeded data.
The issue is that I need to re-seed the data, I need to have data with current dates for testing purposes.
I have created model and seeding in OnModelCreating method and it works fine for creating and seeding new database.
In OnModelCreating method, I am using HasData for seeding:
modelBuilder.Entity<User>().HasData(PatientMockDB.Users);
modelBuilder.Entity<VisitReview>().HasData(PatientMockDB.VisitReviews);
modelBuilder.Entity<Visit>().HasData(PatientMockDB.AllVisits);
In PatientMockDB static class I have new data that I want to have in db.
OnModelCreating method is run whenever I run the app and want to take something from db.
When I delete db, delete migrations then EF will create db with new data, but I would prefer not to do it everyday, again.
How to force data update without deleting db?
Additional question, what is the best way to omit running OnModelCreating when database is already generated with up to date data or when on production?

ASP.NET Core MVC local database and model controller

I have created an ASP.NET Core web application using the MVC pattern (by following this tutorial) and connected it to a local database that is now populated with some data. I have two questions, if someone please help me understand and answer them:
1) My default connection string is set to the following:
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-MyAppName;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Is it possible, only by changing the name and path in this connection string, to re-create the exact same database elsewhere with the data that is currently stored in it (for example, as backup)?
I have found the local database here:
C:\Users\my-name\AppData\Local\Microsoft\Microsoft SQL Server Local DB\Instances\MSSQLLocalDB
But when I try to copy the .mdf file to back up the database, I get an error that says the file is open and cannot be copied. What is it open in? How can I simply back the db file up?
2) After creating a custom controller, I noticed that all the provided properties of my Personmodel are used in the auto-generated code; e.g. in my case:
public async Task<IActionResult> Create([Bind("Birthday,ID,Username,EmailAddress")] PersonModel personModel)
I thought this would mean that if we change the code in the model class, we need to search for and effect the changes accordingly, but then I realized if I want to keep using auto-generated code, I have to do all the same steps as when I am generating it for the first time, and then when it asks if I want to replace the old code with new code, I choose yes.
Is there a better way of doing this, because this would overwrite my custom code every time and destroy the data stored in my local database. Particularly, when I store data in its local database, and then I decide to change a column name or add something, this would override everything...
How do I go about this situation?
Question 1
The .mdf and other files associated with the database will be in use by the SQL Server service. If you want to take a backup, use SQL Server Management Studio - right-click the database in the object explorer, select Tasks and then Backup. If you want to use the backup database then you need to restore it - again in the object explorer, right-click the "Databases" folder and select Restore Database and then browse to wherever you created the backup file.
Question 2 (updated 7th Sep)
When you change your model classes, you can use the add-migration command in the console to generate a new migration class containing the code to transform the database from its current structure to the new structure which matches the updated models. If the migration can cause data loss, then backup the database and restore the backup under a different name before running update-database, You can then create a script to transform the data from the backup into the new structure of the updated database.
Scaffolded components are a bit different to Entity Framework migrations. Migrations are truly auto-generated classes, and most of the time you wouldn't need to update (or even look at) the generated code. Think of scaffolded components as being more like a kind of template - it's a way of getting started with the classes, methods, markup etc that you're most likely to need, which is quicker than writing it all from scratch. It's not an alternative to writing code though, the intent is that once you've created the scaffolded code, you'll maintain it manually going forward. There is no way (that I know of) to automatically update scaffolded code to match a new model whilst retaining any edits you've made to it. You have two options
Re-scaffold the code and then apply your edits to it
Update the code manually to match the new model
All you can really do is weigh up the two options and decide which one is the least effort.

EF Core 3.1 DB First to Code First update old database

The project at the moment is using Database first approach, now we are switching to code first for various reasons.
using Scaffold-DbContext I have generated DbContext (we already have, but probably it will be less error prone) from one of dev environments where they are latest changes applied. Removed the copied .HasConstraintName(""); and .HasName(""); in .OnModelCreating() and I've created the Initial migration. So far so good.
The problem comes with updating existing database which is old compared to latest and as well keep the data.
What is the best way to update the database with the migrations?
I've added this in the Configure() method under Startup.cs to create the database if doesn't exists with the migrations, but not sure how to update old, existing one which doesn't have migration history table.
if (!context.Database.EnsureCreated())
context.Database.Migrate();
One solutions is to create an initial migration from your old database and put the MigrationId (example : 20200609075705_Initial ) manually into the dbo.EFMigrationHistoryTable.
After that you can add new migrations without any problem .

Do I need a migration for EF code first when the database does not exist in SQL Azure?

I have tried lots of variations of EF migration v6.0.1 (from no database, to empty databases to existing databases) and I have a particular problem with Azure DB instances not being able to correctly be created on first deploy using Octopus deploy.
There are a number of places where this could be going wrong, so I thought I would check some basics of EF Code First migration with you fine people if I may:
If I create a code-first model, and know that the database does not exist in the intended target database server on Azure. With the default of 'CreateDatabaseIfNotExists' approach and with AutomaticMigrations disabled;
If I then call 'migrate.exe' with the assembly containing my DbContext and migration Configuration will I get a new database created with the current state of the model? or will I get a new database with nothing in it? i.e. do I need to explicitly 'add-migration' for the initial state of the model?
I have read in the documentation that the database instance should be created automatically by the migration process, but no one states clearly (at least to me) that this newly created database will be generated with the current model without a formal 'initial state' migration created.
So the question is this: do I need an explicit migration model generated for migrate.exe to work from?
Through whatever means I try, I get a database but the application launches with the unfriendly message "Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations." Remembering that this is the same application library that just created the database in the first place (from scratch) I fail to understand how this has happened!
I did manually delete the target database a few times via SQL Server management studio, is this bad? Have I removed some vital user account that I need to recover?
Migrations and the Database Initializer CreateDatabaseIfNotExists are not the same.
Migrations uses the Database Initializer MigrateDatabaseToLatestVersion, which relies upon a special table in the database _MigrationsHistory.
By contrast, CreateDatabaseIfNotExists is one of the Database Initializers which relies upon the special database table EdmMetadata. It does exactly as it implies: Creates a database with tables matching the current state of the model, i.e. a table for each DbSet<T>, only when the database does not exist.
The specific error you have quoted here, Model compatibility cannot be checked because the database does not contain model metadata., occurs due to the existence of DbSet<T> objects which were added to the code base after the initial database creation, and do not exist in EdmMetadata.
There are 4 basic Database Initializers available, 3 of which are for use when migrations is not being used:
CreateDatabaseIfNotExists
DropCreateDatabaseWhenModelChanges
DropCreateDatabaseAlways
Also note, the 4th Initializer, MigrateDatabaseToLatestVersion, will allow you to use Migrations even if AutomaticMigrations is disabled; AutomaticMigrations serves a diffierent purpose, and does not interact with the Database Initializers directly.
If you intend to use Migrations, you should change the Database Initializer to MigrateDatabaseToLatestVersion and forget about the other 3. If, instead, you intend to not use Migrations, then the choice of Initializer is situational.
CreateDatabaseIfNotExists will be more appropriate when you are certain that your data model is not undergoing active change, and you only intend to be concerned with database creation on a new deployment. This Initializer will elp ensure that you do not have any issues with accidental deletion of a database or live data.
DropCreateDatabaseWhenModelChanges is most appropriate in development, when you are changing the model fairly often, and want to be able to verify these changes to the model. It would not be appropriate for a production server, as changes to the model could inadvertently cause the database to be recreated.
DropCreateDatabaseAlways is only appropriate in testing, where your database is created from scratch every time you run your tests.
Migrations differs from these 3 Database Initializers, in that it never drops the database, it instead uses Data Motion to execute a series of Create Table and Drop Table SQL calls.
You also can use Update-Database -Script -SourceMigration:0 in the Package Manager Console at any time, no matter which Database Initializer you are using, to generate a full SQL script that can be run against a server to recreate the database.
Firstly, many thanks to Claies who helped me get to the bottom of this problem. I have accepted his answer as correct as ultimately it was a combination of his response and a few additional bits of reading that got me to my solution.
In answer to the actual posts question 'Do I need a migration for EF code first when the database does not exist in SQL Azure?' the answer is yes you do if you have disabled automatic migrations. But there is a little more to be aware of:
The Azure aspects of this particular problem are actually irrelevant in my situation. My problem was two-fold:
The migration being generated was out of sync with respect to the target model. What do I mean? I mean, that I was generating the migration script from my local database which itself was not in sync with the local codebase which created a migration that was incorrect. This can be seen by comparing the first few lines of the Model text in the __MigrationHistory. This awareness was helped by referring to this helpful post which explains how it works.
And more embarrassingly (I'm sure we've all done it) is that my octopus deployment of the web site itself (using Octopack) somehow neglected to include the Web.Config file. From what I can tell, this may have occurred after I installed a transform extension to Visual Studio. Within my nuget package I can see that there is a web.config.transform file but not a web.config. Basically this meant that when the application started up, it had no configuration file to turn to, no connections string at all. But this resulted in the slightly misleading error
Model compatibility cannot be checked because the database does not
contain model metadata.
Whereas what it should have said was, there isn't a connection string you idiot.
Hopefully this helps people understand the process a little better after reading Claies answer and also that blog-post. First though, check you have a web.config file and that it has a connection string in it...

EF Database first how to update model for database changes?

In a class library Ado.net Entity Data Model is has generated POCO classes. These were generated fine for the first time. But database changes are not being reflected. In edmx diagram right clicking and choosing Update Model from Database show newly created table but it do not add table even after selecting it to add.
I tried running .tt (by right click and Run custom tool) but even it did not regenerated the Poco classes as per latest DB changes.
Help please
Not a fix but a workaround: Is it not an option to simply remove and regenerate the EDMX and the generated classes? That's what I do, it is much easier than working with the update feature, and the result seems to be the same. Your POCO extensions still remain the same and functional.
I use database first and I have my SQL upgrade scripts, the generated EDMX and my Generated models in source control and the changes there are very easy to manage. Here is a rough outline of my DB upgrade process for each version:
Create .sql script for the upgrade, statements like CREATE TABLE etc.
Delete generated files: Model.Context.tt, Model.tt, Model.edmx
Remove Entities string from Web.config (if you use it)
Create the EDMX and Context files the same way you did for the first time
If you use source control (I hope you do!) check what has changed
Test
Commit!
In my case i needed to save ModelName.edmx, then classes were generated.
Ensure that connections string in app.config is correct. I was using a DataDictionary and my connection string had the following path:
data source=|DataDirectory|*.sqlite
Thus, it wasn't updating. Because this DataDirectory variable was being resolved at runtime.

Categories

Resources