pretty new to SQL cascading delete. I was wondering how cascade delete works when it comes the children. So say I have a table situation like:
ParentTable ==Cascade==> ChildTable ==NoCascade==> GrandChildTable
Will the grandchild also be deleted? Do I need to specify in the childtable to turn off cascade delete? I am using Fluent API to set the cascade delete for the parent ParentTable to the ChildTable with WillCascadeOnDelete(true), should I set WillCascadeOnDelete(false) on the ChildTable, is this necessary? The reason I can not delete the GrandChildTable is because it is a domain table.
Thanks,
Matt
Will the grandchild also be deleted?
No, not if your database system is not completely buggy, or lets say incompletely implemented (and this has not much to do with entity framework). If that would be possible, you could easily destroy data integrity against the intentions of those foreign key constraints.
If you want grandchilds to be deleted when a child gets deleted, you need an additional DELETE CASCADE constraint on the FK relation from ChildTable to GrandChildTable. It does not matter if the DELETE operation on the child comes from an explicit DELETE for that child, or from a cascading delete for the parent.
Related
If a parent table has multiple child tables, wouldn't it make more sense to declare ON DELETE CASCADE on the parent table? This way, it wouldn't be necessary to add ON DELETE CASCADE on each of the child tables.
First -- and obviously -- you might not want on delete cascade on all foreign key relationships. Each foreign key can have its own behavior, which is defined where the foreign key is defined.
Also very important. The deletion behavior is assigned on the attribute associated with the table where the deletion is going to occur. That is much more in the spirit of SQL -- and sanity -- than having a master table decide to just delete records in a bunch of other tables.
I need to delete records from relational database, where I attempt to start from the lowest children in the database.
I'm not very strong on how to approach the task. I don't want to do CASCADE delete, I actually want to do the opposite of CASCADE.
Is is correct that I have to find the entity that does not have child and start deleting the records there? and what if an entity has more that one foreign key, how do I decide on which parent table should I start to delete from?
You have to delete the child records first. If you try to delete a record that is referenced with a foreign key, you will get an error which should indicate which key has a conflict. You can then see which child table is impacted and delete the records that are referencing the foreign key, then try again.
You simply work your way up the chain. If more than one child record references a parent record, you simply delete all the child records first. If more than one parent record is referenced by a child record, it doesn't matter which parent is deleted first (or if they are deleted at all).
You don't give what database and what tools you have at hand.
You could manually diagram the database based on foreign keys or you could use a tool, such as visual studios to diagram your database.
As long as the multiple foreign relationships don't depend on one another it shouldn't matter where you start.
Let's say I have 3 tables in a hierarchy:
TableA -> TableB -> TableC
TableC has a foreign key relationship with TableB, and TableB has a foreign key relationship with TableA.
If i delete a record in TableA, it should cascade delete down through the hierarchy. Using ON DELETE CASCADE would work fine.
However let's say I need to put an INSTEAD OF trigger on TableC. My understanding is that an INSTEAD OF trigger can not be put on a table that has a delete cascade going to it. Taken from MSDN:
For INSTEAD OF triggers, the DELETE option is not allowed on tables that have a referential relationship specifying a cascade action ON DELETE.
If I have to take the cascade delete off TableB->TableC, I would need to use an INSTEAD OF trigger to enforce Referential Integrity, and then I have the same problem with TableB->TableA. This is a simple example, but imagine the cascade path being much larger. It seems like it could easily snowball throughout a long cascade path.
So what are the best practices for dealing with this scenario?
Assuming you must use INSTEAD OF triggers, and AFTER triggers are not an option, the best approach is to a) tightly control the schema so that you can b) script the INSTEAD OF triggers out in a regular fashion to implement the CASCADE DELETE and whatever other operations you need.
Create the FK constraints as before, but w/out any cascade behavior. In the FK name, use some convention to indicate what kind of cascade behavior and custom behavior should occur, eg:
FK_UC_DC_Table1_Table2 -- update cascade, delete cascade
FK_UC_DN_Table1_Table3 -- update cascade, delete set null
Use whatever makes sense, but do create the FKs, they are useful metadata for code generation, and you can use the FK names to record directives for the code-generator.
I'd then take it a step further and isolate these tables in their own schema. They won't behave the same way as other tables, and they will be more buggy at first as you test and fine-tune the code generation. Best to keep all this quarantined, and easily identifiable by a common container.
A dedicated schema will also inform anyone modifying the data that different rules and behavior apply.
The standard best-practice is to define INSTEAD OF triggers on views, not on tables.
If you have to use a trigger on a FK update/delete you are best to use AFTER, since it will always execute.
If you want to cancel the cascading actions but retain the FKs, just set the FK action to NO ACTION.
Let's say I have a row in Table A I wish to delete but there a multiple foreign key constraints in other tables. Is there a way to automatically generate the delete command?
I think a tool that would recursively look at the foreign keys and in turn generate a delete statement to take care of all foreign keys should exist, but I can't find one.
I'm on MSSql server2008
When setting up your Foreign Key relationships there is an ON DELETE CASCADE you can add.
MSDN Cascading Referential Integrity Constraints
ON DELETE CASCADE
Specifies that if an attempt is made to delete a row with a key referenced by foreign
keys in existing rows in other tables, all rows containing those foreign keys are also
deleted. If cascading referential actions have also been defined on the target tables,
the specified cascading actions are also taken for the rows deleted from those tables.
SO even has a solution where you are not adding it to the table:
In SQL Server 2005, can I do a cascade delete without setting the property on my tables?
I have the following table relationship in my database:
Parent
/ \
Child1 Child2
\ /
GrandChild
I am trying to create the FK relationships so that the deletion of the Parent table cascades to both child and the grandchild table. For any one particular granchild, it will either be parented to one or the other child tables, but never both at the same time.
When I'm trying to add ON DELETE CASCADE to the FK relationships, everything is fine adding them to one "side" of the two children (Parent-Child1-GrandChild is fine for Cascade Delete). However, as soon as I add the Cascade Delete on the Child2 "side" of the relationship SQL tells me that the FK would cause multiple cascade paths. I was under the impression that multiple cascade paths only apply when more than one FK indicates the SAME table. Why would I be getting the multiple cascade paths error in this case?
PS The table relationships at this point would be very difficult to change so simply telling me to change my table structure is not going to be helpful, thanks.
The message means that if you delete a Parent record, there are two paths that lead to all deletable GrandChild records.
Fix: Remove the ON DELETE CASCADE options in the FKs, and create INSTEAD OF DELETE triggers for the ChildX tables, deleting all grandchild records, and then the childX records themselves.