Remap foreign key constraint after table rename with EF Core code first migration - entity-framework-core

I have to rename a table A that is targetted by a foreign key constraint of another table C. I then have to add a new table B and remap the old foreign key constraint link "A <-> B" to C, so that now B and C are linked.
How can I do that with Blazor, EF core code first? It would be ok the remove the foreign key constraint "A <-> C" and create a new "B <-> C" one. I just don't know how to write that down as C# migration code.
Background: The automatically created migration didn't work due to exactly that foreign key restriction. Instead of simply renaming everything, code for dropping the table and recreating it was created, causing a foreign key constraint error during execution of the migration. So I rewrote it to simply rename the table and create the new one, but that remapped the foreign key to the renamed table, which is not what is needed.

I found the answer myself: I can use migrationBuider.DropForeignKey() and migrationBuilder.AddForeignKey().

Related

Entity framework - referencing one of composite primary key columns as a foreign key

In table A I've got a composite of 3 columns as a primary key. I want to have only one of these three columns as a foreign key in table B, just to make sure that the value that I insert into table B's column exists in table A.
Currently from what I've read it looks like in Entity Framework I have to add all three columns of composite PK, which is not really what I need. The latest answer that I've found was of 2015, maybe since then something changed?
I know that I can add a manual check on each insert/update call, but I don't want to do that, maybe there is more elegant way.

Entity Framework 6 Casscade Deletes and DropForeignKey fails on auto generated constraint name

Entity Framework 6 Casscading Deletes and DropForeignKey fails on auto generated constraint name
I've been running into a bit of an issue with Entity Framework and cascade deletes between two tables on several one-to-many relationships.
Initially it looked like the correct path to take was to configure the table mappings with the OnModelCreating method of DbContext turning off cascade delete in a manner such as
modelBuilder.Entity<SourceTable>()
.HasOptional(x => x.NavigationProperty)
.WithOptionalDependent()
.WillCascadeOnDelete(false);
This however did not work throwing an exception stating
Cannot delete or update a parent row: a foreign key constraint fails...
More research lead me to believe that this is because all affected entities must be loaded into the context (eager fetched) so that entity framework may set the FK references to null as part of the transaction. This is not practical for my needs based on the size of the relational graph I'd be dealing with.
My next approach was to modify the Seed method of the Configuration class and run some arbitrary SQL to drop the Foreign Key constraint and re-add it as a ON DELETE SET NULL constaint. This worked in most cases, however one of the consraints has what appears to be an auto generated unpredicatable name that is diffrent on each call of Update-Database. Given that the name can't be predicted the ALTER statments aren't particualr helpful
context.Database.ExecuteSqlCommand(#"ALTER TABLE SourceTable DROP FOREIGN KEY FK_9405957d032142c3a1227821a9ed1fdf;
ALTER TABLE SourceTable
ADD CONSTRAINT FK_ReasonableName
FOREIGN KEY (NavigationProperty_Id) REFERENCES NavigationProperty (Id) ON DELETE SET NULL;");
Finally, I've taken the apprach to use the migration functionality (DbMigration) and override Up method and leveraging the DropForeignKey method along side more explicit SQL to re-add the constraint (EF does not appear to provide a factility to create a ON DELETE SET NULL constraint).
DropForeignKey("SourceTable", "NavigationProperty_Id", "DestinationTable");
Sql("ALTER TABLE SourceTable ADD CONSTRAINT FK_ReasonableName FOREIGN KEY (NavigationProperty_Id) REFERENCES DestinationTable (Id) ON DELETE SET NULL;");
This works great, up until I encounter the constraint with the auto generate name. At this point the DropForeignKey method fails with an exception that is swallowed up by
System.Runtime.Serialization.SerializationException: Type is not resolved for member 'MySql.Data.MySqlClient.MySqlException,MySql.Data...
When dumping the migration to a SQL script file it becomes clear that the DropForeignKey simply generates a FK with a more predictable, non-ambiguous byte stream array.
Is there a proper EF Code First approach to solve the problem of setting FK column values to null when deleting the refrenced row, or am I stuck having to hand code SQL in order to gain this functionality?

Errors creating constraint trigger

Let me start by saying that I’m a Linux/Unix admin. That being said my manager has tasked me with moving older PostgreSQL databases to a RedHat server running 8.4.20. I was successful moving a 7.2.1 db but I’m running into issues moving a 7.4.20 db.
I use pg_dump –c filename and psql < filename. For the problematic db everything runs until I get to a CREATE CONSTRAINT TRIGGER statement. If I run it as it is in the file I get :
NOTICE: ignoring incomplete trigger group for constraint "" FOREIGN KEY data(ups) REFERENCES upsinfo(ups)
DETAIL: Found referenced table's DELETE trigger.
CREATE TRIGGER
If I run set schema 'pg_catalog'; I get:
ERROR: relation "upsinfo" does not exist
The tables (I think) involved are:
CREATE TABLE upsinfo (
ups text NOT NULL,
ipaddr inet,
rcomm text,
wcomm text,
reachable boolean,
managed boolean,
comments text,
region text
);
CREATE TABLE data (
date timestamp with time zone,
ups text,
mib text,
value text
);
The trigger problem trigger statement:
CREATE CONSTRAINT TRIGGER "<unnamed>"
AFTER DELETE ON upsinfo
FROM data
NOT DEFERRABLE INITIALLY IMMEDIATE
FOR EACH ROW
EXECUTE PROCEDURE "RI_FKey_cascade_del"('<unnamed>', 'data', 'upsinfo', 'UNSPECIFIED', 'ups', 'ups');
I know that the RI_FKey_cascade_del function is defined differently in the different versions of pg_catalog. Note that search_path is set to ‘public, pg_catalog’ so I’m also confused why I have to set the schema.
Again I’m not a real PostgreSQL DBA so try to be kind.
Oof, those are really old postgres versions, including the version you're upgrading to (8.4 was released in 2009, and support ended in 2014).
The short answer is that, as long as upsinfo and data are being created and populated, you're probably fine, and good to go. But one of your foreign key relationships is broken.
The long answer, well, let me see if I can explain what is going on (or, at least, what I think is going on).
I'm guessing that the original table definition of data included something like FOREIGN KEY (ups) REFERENCES upsinfo (ups) ON DELETE CASCADE. That causes postgres to automatically make some trigger constraints: 1- every time there's a new row for data, make sure that its ups column matches an existing row in upsinfo, and 2- every time you delete a row from upsinfo, delete the corresponding rows in data, based on the matching ups value.
That (not very informative) error message can come up when the foreign key relationship doesn't work. In order for a foreign key to make sense, the referenced value needs to be unique -- there should be only one row in upsinfo for each distinct value of ups. In order for postgres to know that, there needs to be a unique index or primary key on upsinfo.ups.
In this case, one of a couple things could be breaking it:
There's no primary key or unique index on upsinfo.ups (postgres should not have allowed a foreign key, but may have in very old versions)
There used to be a unique index, but it hadn't properly enforced uniqueness, so it didn't get successfully imported (a bug, again likely from a very old version)
In either case, if that foreign key relationship is important, you can try to fix it once the import is complete. Start by trying to make a unique index on upsinfo.ups, and see if you have problems. If you do, resolve the duplicate entries, and try again till it works. Then issue something like:
ALTER TABLE data
ADD FOREIGN KEY (ups) REFERENCES upsinfo (ups) ON DELETE CASCADE;
Of course, if things are working, it's possible you don't need to fix the foreign key, in which case you're probably able to ignore those errors and just move forward.
Hope that helps, and good luck!
This seems to be a part of ON DELETE CONSTRAINT. If I were you I would delete all such statements and replace them with a proper constraint definition on the target table.
Table definition should then look like this:
CREATE TABLE bookings (
boo_id serial NOT NULL,
boo_hotelid character varying NOT NULL,
boo_roomid integer NOT NULL,
CONSTRAINT pk_bookings
PRIMARY KEY (boo_id),
CONSTRAINT fk_bookings_boo_roomid
FOREIGN KEY (boo_roomid)
REFERENCES rooms (roo_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
) WITHOUT OIDS;
And this part is what will internally create the trigger:
CONSTRAINT fk_bookings_boo_roomid
FOREIGN KEY (boo_roomid)
REFERENCES rooms (roo_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
But, to be honest, I do not have an understanding for an upgrade to an unsupported version. You know the Postgres is version 9.5 now, right?

Cannot make a relation to table with deferrable primary key

I'm building my first PostgreSQL database. Now it's just two tables (table A with 1:N relation to table B). Table A has a non-deferrable primary key, while table B has a deferrable primary key. When I try to add table C with a foreign key pointing to primary key of table B (another 1:N relation), PgAdmin refuses to create the table and it returns an error message:
ERROR: cannot use a deferrable unique constraint for referenced table
"table_B"
From my previous searches deferrable primary key seemed to be normal solution. Is it really possible in PgAdmin? Do I need some special trick for this to run?
I use PostgreSQL 9.1.3 and PgAdmin III 1.14.3 on 32 bit Windows XP.
I believe it's not possible. Quote from PostgreSQL docs about foreign key:
The referenced columns must be the columns of a non-deferrable unique
or primary key constraint in the referenced table.

django: manually adding a foreign key column (newcolumn_id_refs_id_4bfb2ece ?)

I need to add a foreign key field to an existing django model/postgres table. As per the django documentation, I ran the 'sqlall myapp' command to 'work out the difference'.
The obvious difference is that the table in question now has an extra column with a new contraint, which looks like this:
ALTER TABLE "myapp_mytable" ADD CONSTRAINT newcolumn_id_refs_id_4bfb2ece
FOREIGN KEY ("newcolumn_id") REFERENCES "myapp_theothertable" ("id")
DEFERRABLE INITIALLY DEFERRED;
Before messing with my database, I'd like to understand that statement, in particular, what does the last part of newcolumn_id_refs_id_4bfb2ece refer to?
Thanks,
Martin
It will make PostgreSQL understand and enforce your foreign key to the other table and guarantee there won't be anything in myapp_table.newcolumn that can't be found in myapp_theothertable.id
Actually, your django app will work just fine even without that constraint. However, it's a good idea to have one in place, and if you do afterwards a dumpdata - loaddata -cycle, it will be created.