EF Core Code First Automatic Column Not Deletable - sql-server

I have a Code-First .Net Core project using Entity Framework Core (2.0).
There are two tables, RhythmBlock and RhythmPattern.
Based on a List<RhythmBlock> property on RhythmPattern, EF created a column on RhythmBlock of RhythmPatternId, which I didn't really want.
So I tried all the following:
Mark the List<RhythmBlock> with the Annotation [NotMapped] and update db.
User FluentAPI to tell the db to Ignore and update db.
Delete the List<RhythmBlock> and replace with a method that returns the same, updated db.
All sorts of shenanigans with resetting the Migrations, direct sql, etc.
The results of all my attempts were that anytime I deleted the column RhythmPatternId in table RhythmBlocks, I would get the error Invalid Column Name. Even if the column and all indexes and foreign keys were deleted, all reference removed from the project, the error would continue.
The only way to get my project running again? Add back in the deleted column. So it's working, but I don't understand why?

Related

Rename table or column in SQL server without breaking existing apps

I have an existing database in MS SQL server and want to rename some tables and columns because the names currently used aren't accurate to what it represents.
I have multiple web and desktop applications that access the database, using Entity Framework (code first). Too many to update in one go and cannot afford for all apps to start working.
I was thinking it was nice is SQL server allowed a 'permanent' alias for tables and columns but I don't think this feature exists.
Or I was wondering if there was a way in EF to have two names for the same property?
For the tables, you could rename them and then create a synonym with the old name pointing to the new name.
For the columns, changing their name will break your application.You could create computed columns with the old name as well, that simply display the value of the new named column though (but this seems a little silly).
Note, however, that a computed column cannot reference another computed column, so you would have to duplicate the column in its entirety. That could lead to problems down the line if you don't update the definition of both columns.
A view containing a simple select statement acts exactly like a table. You really need to fix this properly across the database and applications. However if you want to go the view route, I suggest you do this:
Say you have a table called MyTable that you rename TheTable and with a column called MyColumn that you want to rename to TheColumn
Create a schema, say, new
Move the original table into it with this ALTER SCHEMA new TRANSFER MyTable
Rename the table and column.
Now you have a table called new.TheTable with a column called TheColumn. Everything is broken
Lastly, create a view that looks just like the old table
CREATE VIEW dbo.MyTable
AS
SELECT Column1, Column2, Column3, TheColumn As MyColumn
FROM new.TheTable;
Now everything works again.
All your fixed 'new' tables are in the new schema
However now everything is extra complicated
This is basically an illustration that you should just fix it properly across the whole app one at a time with careful change management. Definitely don't complicate it with triggers
Since you are using code first with multiple web and desktop applications, you are likely managing database changes from one place through migrations and ignoring changes other places.
You can create an empty migration and add code that will change the table name and column names to what you want. The migration should then create a view that will select from that table with the original table and column names. When you apply this migration, everything should still be working as normal from all applications. There are no model changes since you didn’t touch the model classes. Inserts, updates, and deletes will still happen through the view. There is no need for potentially buggy triggers or synonyms on the table in this option.
Now that you have the table changed, you can focus on the application code. If it helps, you can add annotations over the column and table names and start refactoring the code. You need to make sure you don’t make model changes that will break the other apps. If apps ignore model changes, you can get away with adding annotations over the columns and classes on all the apps before refactoring. You can get rid of the view sooner this way.

JPASpringDataRepository partial save

I am creating a web application with Spring Boot which uses Spring Data JPA for the database access. I have created a Repository class that extends the JpaRepository as follows:
public interface MyRepository extends JpaRepository <MyClass, Integer>{
}
I am invoking this method from my controller as follows:
myRepo.save(myclassList); //myclassList is a List<MyClass>
In the database table corresponding to myclass, there is a unique constraint on one of the columns. So if the constraint is violated, an exception is thrown. However ideally, I would want the save method to work for those records that do not violate the constraint. However sadly this is not the case. So if the unique constraint is violated for even one record, none of the records get inserted into the database. Is there any workaround for this? Or will I need to manually check each record to see if it exists in the DB and only insert the ones that do not exist in the database?
will I need to manually check each record to see if it exists in the DB and only insert the ones that do not exist in the database?
Short answer
Yes.
Longer Version
The exact way to proceed depends on your specific use case. I see the following options:
Make sure your data is valid before you save it. This is probably the default approach
Save each entity in a separate transaction, this way the rollback will only rollback the changes to that one entity.
Try to save everything in one transaction. If it fails fallback to 1. or 2. This is a little more coding but probably has the best performance if constraint violations are a rare event.

DACPAC package with complex changes

I'm looking to switch to DACPACs for our database changes, but I'm a bit at a loss about what to do when it comes to more complex database updates. To illustrate what I mean, let me use a simple example that has the same problem.
Say I have a Customer table that is currently live and I want to add a new CustomerType table with a foreign key from Customer to CustomerType. The new column in Customer should be required (not nullable), but should not have a default value.
I want to use some arbitrary formula to setup the initial type for the existing customers upon upgrading. How would I accomplish this using a DACPAC?
The DACPAC will only know there's a new column and will try to add it to the Customer table, which will of course fail because it is required. Setting a default value is undesirable, as is allowing null values.
Since the DACPAC should be usable to upgrade from every state to the latest, I don't see what kind of configuration or pre/post scripts I should setup to make this work.
Various searches have produced a disappointing lack of useful results :(
I hope there's someone here that can help out. Thanks in advance.
The answer will vary a bit depending on how you're planning to deploy the dacpac(s). One common case is having the dacpac replace some collection of T-SQL update scripts that are executed in sequence to update a database schema from one version to the next. In this case you might choose to have one dacpac file for each schema-version of your database and to update a database you would plan to publish the dacpacs in sequence to update a database to the latest version.
In that case, it's possible to use a post-deploy script to fix up the schema as appropriate. For your example scenario, you can model the database in the database project with the new column specified as NULL and without the FK relationship with the new table. Then, in a post-deploy script you can author the T-SQL necessary to execute an UPDATE statement to fill the new table and the new column, an ALTER statement to change the column's type from NULL to NOT NULL, and finally to add the foreign key relationship.
Then moving forward you can remove the post-deploy script and model the new column and table with the proper column type and FK relationship.

Remove Linq to SQL Association on Multi-Client DB

I have a multi-client DB (multitennant) with several tables.
Two of these tables are tblEmployees and tblTitles.
Now I have a relationship from tblEmployees.empTitle to tblTitles.ttlID.
That far everything is working.
But now I have to make the application for multiple clients/tennants.
So I added the fields tblEmployees.empClient and tblTitles.ttlClient and included them into the association.
This works fine for reading and for setting the persons title as well.
But if I try to remove the title (set it to NULL), SQL to Linq tries to modify both tblEmployees.empTitle and tblEmployees.empClient with is not allowed because tblEmployees.empClient is part of the primary key.
And so I get the following error:
InvalidOperationException:
An attempt was made to remove a relationship between a AppTitle and a AppEmployee.
However, one of the relationship's foreign keys (AppEmployee.clientID, AppEmployee.titleID) cannot be set to null.
How can I tell SQL to Linq only to modify field tblEmployees.empTitle???
I just solved the problem as everyone else did:
I let LinqToSQL think, clientID was not part of the primary key and removed it from the association.
However I did not modify the database, so the database still enforces to use a title of the same client/tennant.

Database "Identity" field and auto-increment

I'm writing my first database application and I've got an ambiguity I can't seem to find an answer for. I have an id field that is the identity set to auto-increment. My issue is trying to determine when the field is incremented. Is the field incremented when I call an instance of the object, when I call the AddObject method of the ObjectContext class, or when I call the SaveChanges method from an Entity model.
In my relational database each table has both a unique ID for that table and one that represents a group of users. After I create an instance of an object for that table I want to run a query (LINQ) that searches two tables to match two records and from one of those tables copy that group ID back to the individual user.
That or it is blatently obvious I know nothing about how relational databases work,
The identity field is handled by the database. It is created by the database when the row is inserted. The generated id is read back by SaveChanges and the entity object is updated.
WHen you add a new row to the database the counter is incremented.
If you have an ambiguity, this usually means that two tables fields are the same name, and your query doesn't know which one you want. Can be solved by defning which table the column is ment for.
I don't know LINQ, so hopefully someone can give you a more direct answer.

Resources