EF Code First Migrations and Foreign Key Constraints - sql-server

Once FK Constraints have been created via Entity Framework Core 1.1 with Migrations in an ASP.NET Core Code First app, would it be ok to temporarily enable/disable the constraints directly in SQL Server without using EF - would it break the migrations created via EF etc? Background: I need to truncate data from a table that has been referenced by several tables via FK's that were created through EF Code First. SQL Server, as expected, complains that you can truncate the table since it's been referenced by a FK etc.

No, it would not break migrations. If you are doing anything on database and then reverting back the schema design of database to earlier state then migration will just run fine. Migrations when applied expect that shape of EF managed objects in database to be remain same (as it would have known earlier). Any temporary change is invisible to migration. And state needs to be same afterwards because when future migrations applied then appropriate objects are present otherwise DDL can cause failure.

Anything you change in the database schema in SQL Server, without the code, will break the migrations. You should delete the foreign key references in the code for the operation you want to do and then recreate them later. Though, be careful, if your data is left in inconsistent state, you might not be able to recreate constraints without losing data.

Related

ASP.Net Core Identity EF 5.0 restore only users to database

I am using the Microsoft.AspNetCore.Identity.EntityFramework in my Blazor Server Project and have customized it with no problem. I do enjoy the simplicity and robustness of the Identity; however, since I am developing for deployment, I came across a small problem. In the disaster recovery, the FULL restore from an MSSQL backup works without a hitch. This type of backup is crucial if you have not changed anything in your ApplicationDbContext for the deployed Blazor Server Project. So for that matter in disaster recovery to a same state and DbContext, there is no issue, but should you have a small change from one install to another in the DbContext, or say you are upgrading the previous version of the Blazor Server Project with changes in the context, you cannot recover the users since you can only do a complete FULL restore with the previous DbContext as the Db Schema and Design.
How can I restore, or better yet, migrate the date from one instance of the DBContext to another? I tried doing a data restore from backup device, but it does not let me do the restore due to the foreign key between the user table and the user claims and user roles tables. Foreign key constraints do not permit me to restore the users with the previous generated GUID which contain vital information link to other data. Say for example one table tracks events that are created by the user, if I re-create the user, it has different GUID than what is registered in the backup.
Any help will be appreciated.
If you query the table for the ASPNetUsers you get the following:
Id UserName NormalizedUserName Email NormalizedEmail EmailConfirmed PasswordHash SecurityStamp ConcurrencyStamp PhoneNumber PhoneNumberConfirmed TwoFactorEnabled LockoutEnd LockoutEnabled AccessFailedCount
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------- ---------------- ---------------------------------- -------------- -----------------
6cd26b55-b0c6-41ae-ac6c-ff9ae3242c3b userone#mymail.com USERONE#MYMAIL.COM userone#mymail.com USERONE#MYMAIL.COM 1 AQAAAAEAACcQAAAAECp/NfxxEWw8fbd0jIrXOGZ/v/ggPscxMIINueP2dUQAihgRwrE1a+t1os/7MwvPCg== OJP4HUHN6FNCXHXETVJTDQLC6RBUCLJS f69a0ff7-9298-4d1f-8faa-e8ab3db3ab70 NULL 0 0 NULL 1 0
9eda9ba1-dd47-4308-ba62-a19381a32d56 usertwo#mymail.com USERTWO#MYMAIL.COM usertwo#mymail.com USERTWO#MYMAIL.COM 1 AQAAAAEAACcQAAAAEFcXpQREt8sfhssYHlH/hRSlk3yX/bGMCYpXpTrid+YLNMFkDr5V45MnIo0JOPmWlw== YLZJSYILLPQZBFGCOJLXKFZB64YXCHIK c389b663-fcd1-4918-b9ed-54bc583666cc NULL 0 0 NULL 1 0
(2 rows affected)
Completion time: 2021-08-06T14:19:46.8143727-07:00
Since the Id is a GUID generated by the EF Core Identity Table, and is linked to the other ASPNetCore tables such as UserRoles, UserClaims, Etc., how can I import user data with the old GUID that was previously generated?
Edit Aug 12 2021
I have found a temporary work-around for the problem. For purpose of explanation I will use APP, OriginalDB, BackedUpDevice (the bak file) and RestoredDB and NewDB.
The OriginalDB I am continuing to work on the model and ASP.Net Core/Blazor application (APP), therefore on ocassions the model changes. I have my App that when it initializes for the first time, it uses the models to create the Database on the server, should it not exist. I use migrations to create the new model to be put on the server at first run. ASP.Net Core Identity facilitates this.
So, the original problem arises only when the model is modified in the APP and the APP needs to re-apply the migration. I don't use subsequent migrations since, once the OriginalDB is in use, there is data and even if the model changes, the data will need to be copied. I have absolutely no problem with this. I can restore from the BackedUpDevice to another Database as the RestoredDB. I then use the RestoredDB to insert the data back into the NewDB, which is a freshly created copy of the OriginalDB schema and the model changes in the APP. Thus, this gives me my data, but I cannot use this method for the ASP.Net Core Identity tables since it uses Foreign Keys.
The work-around that I have found, is that I can safely delete the ASP.Net Core Identity tables, namely AspNetRoles, AspNetUserClaims, AspNetUserLogins, AspNetUserRoles, AspNetUsers, and do a copy schema and table from the RestoredDB to the NewDB. While recreating the tables using this method works, I have the problem that I have also modified these user tables, not only changing the table names, but also adding custom fields as shown primarily in This Article, on future iterations of the APP, there may be additional custom fields and/or changes that affect these tables. Hence why I need to see how I may just copy the RestoreDB user tables data, including the generated GUID for the user with Foreign Keys to the NewDB user tables. Any suggestion will be greatly appreciated.
I obviously don't know everything about your situation, and I don't understand some parts of your explanation at all, but the approach you've outlined is going very far down the wrong road.
EF Core 5.0 migrations allow a lot flexibility in how they are created, maintained, and applied. You should leverage these features to accomplish what you want to do, rather than creating new databases and copying data into them.
Some examples that seem to be applicable to your use case:
From Using a Separate Migrations Project, you may want to consider having two different sets of migrations - one for local development / iteration, and one that just has migrations that take the released application from one version to the next
From Customize migration code, solving your problems with the automated migrations may involve customizing the automatically generated migration code. Or creating empty migrations and writing completely custom code to perform intermediate data migrations steps
From Excluding parts of your model, you may need to exclude certain objects in one DbContext from being included in the migrations for another DbContext (for instance, if your Identity tables are coming from a different DbContext than the rest of your app tables, but you reference the Identity entities in your main app's DbContext)

How to remove all migrations without unapplying them

I have a .NET Core Project with lots of migrations in it. I also have the database (given to me and not generated with migrations on my pc). now
When I try to add a migration I get an error that there are pending migrations and I first need to update database and I you can guess running update-database command gives me:
object ... already exists error
If I remove database update-database command will generate the whole database however there are lots of data in the database that creating data with migrations would wipe them out.
I thought of generating data script from database, then creating database with migrations and then running the script, but the data script is very large and running the script have lots of other issues.
I just need to remove the old migrations but not unapplying them (as it would also remove my tables from database).
And also note that there are no _MigrationHistory Table in the database
If there is no __MigrationHistory table in the database and you want to omit the migrations, you can also comment the Up and Down fields in the migration files and apply migration. It does not affect your database and only add migration record to __MigrationHistory table.
Note: This problem might occur sometimes and using the approach above most probably fix the problem without affecting data. There are of course some other workarounds that can be applied for such a kind of problem.

How to turn off foreign key constraints permanently on SQL database?

Running EXEC sp_msforeachtable #command1="ALTER TABLE ? NOCHECK CONSTRAINT ALL" will disable Foreign keys on existing tables.
What if the tables and insert data queries that enforce foreign key constraints run after this query,?
I am encountering this issue during build automation and What I am ideally look for is a permanent switch to disable all constraints on the database (i can do that since the database is created as a part of build process).
NOTE: See the 5 steps mentioned towards the last to get an idea of the issue faced during build automation
I have created a build step before processing the scripts to disable all existing foreign key constraints. The next step would be package and run all release sql scripts that may contain tables created, data inserted. The earlier build step to disable constraints have no clue about forth coming database tables and insert scripts which will enforce foreign key constraints after running the data insert, failing my build process.
Is there a way i am set a flag in the database to stop checking for foreign keys?
Adding some more context to what i am doing specifically.Automating build using bamboo and following steps are performed on a high level
locate last available deployed db schema
build a database using the schema generated script (no master data copied).
disable all foreign keys (unable to disable FK for tables yet to be created in next step)
merge all release specific db scripts(may contain new db and insert scripts)
apply other transformations like running codegeneration, script compare, delta finding etc.
Step 3 is the challenge.
Note: This is automating a legacy system with 300ish master datables and data, since Codesmith tools are used, schema changes has to be detected and auto generated code has to be checked against last deployed schema. Since the master data is so huge, keeping a reference db with data for build purposes is out of the question hence the referential integrity constraint issue will be more prominent.
The only thing I can think of is to create a DDL trigger which listens for constraints' creation and, if any are detected, drops them. However, I'm not sure this approach is viable if a constraint is created as a part of the create table statement. You should test it thoroughly before using.
Personally, however, I usually solve this by properly ordering the sequence in which the data is inserted. It's much safer, not prohibitively difficult and, last but not least, always possible to do.
Your basic problem is that your database migrations that are creating your database are running in the wrong order. Adjust the order of tables and data insertion so that only data that references already existing data, is inserted at any one time
Turning all the constraints off, loading data, and turning them all back on at the start and end of each script that does DB data alterations, is also an option, but you should separate your scripts that do schema changes from your scripts that do data loading and run all the schema changes first

Truncate all relational tables in SQL Server

I have a relational database in my server where I've used for developing a system. Now I want to make it live and truncate all data from the tables. I've manually deleted data from tables and after that I've run the truncate command, but it show this error :
Cannot truncate table 'dbo.Building' because it is being referenced by a FOREIGN KEY constraint.
Is there any way to empty my database by using a single command? I've searched google, all of them told to use truncate command. But I can not use it for all the tables because the error occurred.
I want to entry data from the ID no 1 in all tables.
Please give me a guideline to truncate all the data from my database.
Now I want to make it live and truncate all data from the tables
You are approaching this completely wrong. Even if you succeed, you will deploy a system which will be impossible to upgrade. As you continue to develop you will modify the development database and then when you have to deploy your next version of your application you'll realize you need to modify the production database and keep all of its data.
Stop the deployment right now and go back to the drawing board to design a proper deployment strategy. I recommend migrations. Another alternative is using diff tools.
Truncating tables is completely irrelevant for what you're actually trying to achieve.
There are two options I could think off..
You need to drop (not just disable ) all foreign keys, then finally run truncate to delete all table data using any method.. and finally recreate all foreign keys
You also can script out only DDL and deploy database using that script instead of providing database to deployment team..

How to partially migrate a database to a new system over time?

We are in the process of a multi-year project where we're building a new system and a new database to eventually replace the old system and database. The users are using the new and old systems as we're changing them.
The problem we keep running into is when an object in one system is dependent on an object in the other system. We've been using views, but have run into a limitation with one of the technologies (Entity Framework) and are considering other options.
The other option we're looking at right now is replication. My boss isn't excited about the extra maintenance that would cause. So, what other options are there for getting dependent data into the database that needs it?
Update:
The technologies we're using are SQL Server 2008 and Entity Framework. Both databases are within the same sql server instance so linked servers shouldn't be necessary.
The limitation we're facing with Entity Framework is we can't seem to create the relationships between the table-based-entities and the view-based-entities. No relationship can exist in the database between a view and a table, as far as I know, so the edmx diagram can't infer it. And I cannot seem to create the relationship manually without getting errors. It thinks all columns in the view are keys.
If I leave it that way I get an error like this for each column in the view:
Association End key property [...] is
not mapped.
If I try to change the "Entity Key" property to false on the columns that are not the key I get this error:
All the key properties of the
EntitySet [...] must be mapped to all
the key properties [...] of table
viewName.
According to this forum post it sounds like a limitation of the Entity Framework.
Update #2
I should also mention the main limitation of the Entity Framework is that it only supports one database at a time. So we need the old data to appear to be in the new database for the Entity Framework to see it. We only need read access of the old system data in the new system.
You can use linked server queries to leave the data where it is, but connect to it from the other db.
Depending on how up-to-date the data in each db needs to be & if one data source can remain read-only you can:
Use the Database Copy Wizard to create an SSIS package
that you can run periodically as a SQL Agent Task
Use snapshot replication
Create a custom BCP in/out process
to get the data to the other db
Use transactional replication, which
can be near-realtime.
If data needs to be read-write in both database then you can use:
transactional replication with
update subscriptions
merge replication
As you go down the list the amount of work involved in maintaining the solution increases. Using linked server queries will work best if its the right fit for what you're trying to achieve.
EDIT: If they're the same server then as suggested by another user you should be able to access the table with servername.databasename.schema.tablename Looks like it's an entity-framework issues & not a db issue.
I don't know about EntityToSql but I know in LinqToSql you can connect to multiple databases/servers in one .dbml if you prefix the tables with:
ServerName.DatabaseName.SchemaName.TableName
MyServer.MyOldDatabase.dbo.Customers
I have been able to click on a table in the .dbml and copy and paste it into the .dbml of the alternate project prefix the name and set up the relationships and it works... like I said this was in LinqToSql, though have not tried it with EntityToSql. I would give it shot before you go though all the work of replication and such.
If Linq-to-Entities cannot cross DB's then Replication or something that emulates it is the only thing that will work.
For performance purposes you probably want either Merge replication or Transactional with queued (not immediate) updating.
Thanks for the responses. We're going to try adding triggers to the old database tables to insert/update/delete records in the new tables of the new database. This way we can continue to use Entity Framework and also do any data transformations we need.
Once the UI functions move over to the new system for a particular feature, we'll remove the table from the old database and add a view to the old database with the same name that points to the new database table for backwards compatibility.
One thing that I realized needs to happen before we can do this is we have to search all our code and sql for ##Identity and replace it with scope_identity() so the triggers don't mess up the Ids in the old system.

Resources